2449 lines
58 KiB
C
2449 lines
58 KiB
C
/*+
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
nmschl.c
|
||
|
||
Abstract:
|
||
This module contains the name challenge functions
|
||
|
||
|
||
Functions:
|
||
|
||
NmsChlInit
|
||
NmsChlHdlNamReg
|
||
ChlThdInitFn
|
||
HandleWrkItm
|
||
WaitForRsp
|
||
ProcRsp
|
||
ChlUpdateDb
|
||
InfRemWins
|
||
|
||
|
||
Portability:
|
||
|
||
This module is portable
|
||
|
||
Author:
|
||
|
||
Pradeep Bahl (PradeepB) Jan-1993
|
||
|
||
Revision History:
|
||
|
||
Modification date Person Description of modification
|
||
----------------- ------- ----------------------------
|
||
--*/
|
||
|
||
/*
|
||
* Includes
|
||
*/
|
||
#include <time.h>
|
||
#include "wins.h"
|
||
#include "nms.h"
|
||
#include "nmsdb.h"
|
||
#include "winsque.h"
|
||
#include "comm.h"
|
||
#include "winsthd.h"
|
||
#include "winsmsc.h"
|
||
#include "winsevt.h"
|
||
#include "winscnf.h"
|
||
#include "nmsnmh.h"
|
||
#include "nmschl.h"
|
||
#include "nmsmsgf.h"
|
||
#include "rplmsgf.h"
|
||
|
||
|
||
/*
|
||
* Local Macro Declarations
|
||
*/
|
||
|
||
|
||
//
|
||
// Computation of the time it can take for a WINS to conduct a challenge
|
||
// (in msecs)
|
||
//
|
||
#define WACK_TTL (((1 << WinsCnf.MaxNoOfRetries) * \
|
||
WinsCnf.RetryInterval) + \
|
||
WAIT_PAD)
|
||
|
||
//
|
||
// WAIT_PAD is used to increase the TTL sent to an NBT node that sent us the
|
||
// name registration request. The pad is on top of the TTL we compute
|
||
// (WACK_TLL) above to determine how much time WINS will take to conduct
|
||
// the challenge. The pad is supposed to take care of the situation where
|
||
// WINS is dragging its feet due to a sudden transient peak in network
|
||
// load or cpu load.
|
||
|
||
#define WAIT_PAD 500 //500 msecs in case WINS is very
|
||
//busy
|
||
|
||
/*
|
||
* Global Variable Definitions
|
||
*/
|
||
|
||
//
|
||
// heap used to allocate work items for the challenge request and response
|
||
// queues
|
||
//
|
||
HANDLE NmsChlHeapHdl;
|
||
|
||
|
||
|
||
/*
|
||
* Local Variable Definitions
|
||
*/
|
||
//
|
||
// It maintains a running count of how many responses to queries/releases are
|
||
// pending
|
||
//
|
||
DWORD scPendingRsp = 0;
|
||
|
||
//
|
||
// The maximum # of requests that the name challenge manager sends at any
|
||
// one time. This number is never allowed to go over
|
||
// NMSCHL_MAX_CHL_REQ_AT_ONE_TIME. In fact after one series of
|
||
// challenges are over (i.e. either they have timed out or we have received
|
||
// responses for them, this counter is reinitialized to 0)
|
||
//
|
||
// This var. is reinitialized to zero when a batch of challenge requests
|
||
// is acquired from the one or more of the challenge request queues
|
||
//
|
||
// It maintains the total # of requests acquired from the request queues.
|
||
//
|
||
DWORD sMaxTransId = 0;
|
||
#ifdef WINSDBG
|
||
DWORD NmsChlNoOfReqNbt;
|
||
DWORD NmsChlNoOfReqRpl;
|
||
DWORD NmsChlNoNoRsp;
|
||
DWORD NmsChlNoInvRsp;
|
||
DWORD NmsChlNoRspDropped;
|
||
DWORD NmsChlNoReqDequeued;
|
||
DWORD NmsChlNoRspDequeued;
|
||
DWORD NmsChlNoReqAtHdOfList;
|
||
#endif
|
||
//
|
||
// We have a dimension 1 larger than the max. number of challenge requests
|
||
// handled at one time so that we can terminate the list with a NULL.
|
||
//
|
||
STATIC PCHL_REQ_WRK_ITM_T spReqWrkItmArr[NMSCHL_MAX_CHL_REQ_AT_ONE_TIME + 1];
|
||
|
||
/*
|
||
* Local Function Prototype Declarations
|
||
*/
|
||
STATIC
|
||
DWORD
|
||
ChlThdInitFn(
|
||
IN LPVOID pThreadParam
|
||
);
|
||
|
||
STATIC
|
||
STATUS
|
||
HandleWrkItm(
|
||
PCHL_REQ_WRK_ITM_T *ppaWrkItm,
|
||
DWORD MaxTransId,
|
||
BOOL fRetry
|
||
);
|
||
|
||
|
||
STATIC
|
||
STATUS
|
||
WaitForRsp(
|
||
VOID
|
||
);
|
||
|
||
STATIC
|
||
STATUS
|
||
ProcRsp(
|
||
VOID
|
||
);
|
||
|
||
STATIC
|
||
STATUS
|
||
ChlUpdateDb(
|
||
BOOL fUpdVersNoOfCnfRec,
|
||
WINS_CLIENT_E Client_e,
|
||
PNMSDB_ROW_INFO_T pRowInfo,
|
||
DWORD OwnerIdInCnf,
|
||
BOOL fRefreshOnly
|
||
);
|
||
STATIC
|
||
VOID
|
||
InfRemWins(
|
||
PCHL_REQ_WRK_ITM_T pWrkItm
|
||
);
|
||
|
||
STATIC
|
||
STATUS
|
||
ProcAddList(
|
||
PCHL_REQ_WRK_ITM_T pReqWrkItm,
|
||
PNMSMSGF_CNT_ADD_T pCntAdd,
|
||
LPBOOL pfAdded
|
||
);
|
||
|
||
/* prototypes for functions local to this module go here */
|
||
|
||
STATUS
|
||
NmsChlInit(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to initialize the name challenge component
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
WINS_SUCCESS or a failure code. The function can also raise an
|
||
exception in case of fatal errors
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
Init in nms.c
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
|
||
/*
|
||
* Create heap for allocating name challenge work items
|
||
*/
|
||
DBGPRINT0(HEAP_CRDL, "NmsChlInit: Chl. Mgr. heap\n");
|
||
NmsChlHeapHdl = WinsMscHeapCreate(
|
||
0, /*to have mutual exclusion */
|
||
NMSCHL_INIT_BUFF_HEAP_SIZE
|
||
);
|
||
|
||
|
||
//
|
||
// Initialize the spReqWrkItmArr elements to NULL
|
||
//
|
||
// ANSI C should do it for us (all externals are initialized
|
||
// automatically, but I am taking no chances). This is
|
||
// init time overhead.
|
||
//
|
||
WINSMSC_FILL_MEMORY_M((void *)spReqWrkItmArr, sizeof(spReqWrkItmArr), 0);
|
||
|
||
|
||
//
|
||
// Create the response event handle. This event is signaled
|
||
// by the UDP listener thread when it stores a response
|
||
// in the spReqWrkItmArr array
|
||
//
|
||
WinsMscCreateEvt(
|
||
TEXT("WinsNmsChlRspEvt"),
|
||
FALSE, //auto-reset
|
||
&QueNmsCrqQueHd.EvtHdl
|
||
);
|
||
|
||
//
|
||
// Initialize the critical section for the response queue
|
||
//
|
||
InitializeCriticalSection(&QueNmsCrqQueHd.CrtSec);
|
||
|
||
//
|
||
//Initialize the queue head for the response queue
|
||
//
|
||
InitializeListHead(&QueNmsCrqQueHd.Head);
|
||
|
||
//
|
||
// Since this thread deals with two request queues instead of
|
||
// one, we need to create one more
|
||
// critical section and event handle and initialize the
|
||
// queue head of this other queue. The second queue
|
||
// will be created when we create the thread
|
||
//
|
||
InitializeListHead(&QueNmsRrcqQueHd.Head);
|
||
|
||
|
||
WinsMscCreateEvt(
|
||
TEXT("WinsNmsChlReplReqEvt"),
|
||
FALSE, //Auto Reset
|
||
&QueNmsRrcqQueHd.EvtHdl
|
||
);
|
||
|
||
InitializeCriticalSection(&QueNmsRrcqQueHd.CrtSec);
|
||
|
||
//
|
||
//
|
||
// Create the name challenge thread. This function will
|
||
// initialize the critical section and the Evt handle passed
|
||
// to it
|
||
//
|
||
RetStat = WinsMscSetUpThd(
|
||
&QueNmsNrcqQueHd, //queue head
|
||
ChlThdInitFn, //init function
|
||
NULL, // no param
|
||
&WinsThdPool.ChlThd[0].ThdHdl,
|
||
&WinsThdPool.ChlThd[0].ThdId
|
||
);
|
||
|
||
if (RetStat == WINS_SUCCESS)
|
||
{
|
||
WinsThdPool.ChlThd[0].fTaken = TRUE;
|
||
WinsThdPool.ThdCount++; //increment the thread count
|
||
}
|
||
return(RetStat);
|
||
|
||
} // NmsChlInit()
|
||
|
||
|
||
|
||
STATUS
|
||
NmsChlHdlNamReg(
|
||
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 is called to handle a name registration that resulted
|
||
in a conflict
|
||
|
||
|
||
Arguments:
|
||
CmdTyp_e - Type of command (challenge, challenge and release if
|
||
challenge succeeds, release -- see nmschl.h)
|
||
Client_e - client (nms or replicator)
|
||
pDlgHdl - Dlg hdl (only if client is nms)
|
||
pMsg - Buffer containing request (only if client is nms)
|
||
Msglen - length of above buffer
|
||
QuesNamSecLen - Length of question name section in buffer
|
||
pNodeToreq - Info about name to register
|
||
pAddOfNodeInCnf - address of node in conflict (i.e. has name) with the
|
||
node trying to register
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
WINS_SUCCESS or a failure code. The function can also raise an
|
||
exception in case of fatal errors
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
NmsNmhNamRegInd, NmsNmhNamRegGrp (in an Nbt thread)
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
#if USENETBT == 0
|
||
BYTE aBuff[COMM_DATAGRAM_SIZE];
|
||
#else
|
||
BYTE aBuff[COMM_DATAGRAM_SIZE + COMM_NETBT_REM_ADD_SIZE];
|
||
#endif
|
||
DWORD BuffLen;
|
||
|
||
DBGENTER("NmsChlHdlNamReg\n");
|
||
|
||
//
|
||
// Before inserting the request, send a WACK. The Time period
|
||
// in the TTL should be equal to WinsCnf.RetryInterval
|
||
//
|
||
// Note: WACK is sent only if pDlgHdl is NON-NULL since that
|
||
// implies that the request is from an NBT thread
|
||
//
|
||
if (pDlgHdl != NULL)
|
||
{
|
||
|
||
COMM_ADD_T NodeToSendWACKTo;
|
||
DWORD WackTtl;
|
||
|
||
if (NMSDB_ENTRY_MULTIHOMED_M(pNodeInCnf->EntTyp))
|
||
{
|
||
WackTtl = pNodeInCnf->NodeAdds.NoOfMems * WACK_TTL;
|
||
}
|
||
else
|
||
{
|
||
WackTtl = WACK_TTL;
|
||
}
|
||
|
||
//
|
||
// Format the WACK
|
||
//
|
||
NmsMsgfFrmWACK(
|
||
#if USENETBT == 0
|
||
aBuff,
|
||
#else
|
||
aBuff + COMM_NETBT_REM_ADD_SIZE,
|
||
#endif
|
||
&BuffLen,
|
||
pMsg,
|
||
QuesNamSecLen,
|
||
WackTtl
|
||
);
|
||
|
||
|
||
//
|
||
// We extract the address from the DlgHdl and don't use
|
||
// the address passed in the name packet since a node
|
||
// can register a name with an address different than
|
||
// its own.
|
||
//
|
||
// RFCs are silent about the above
|
||
//
|
||
NodeToSendWACKTo.AddLen = COMM_IP_ADD_SIZE;
|
||
COMM_GET_IPADD_M(pDlgHdl, &NodeToSendWACKTo.Add.IPAdd);
|
||
NodeToSendWACKTo.AddTyp_e = COMM_ADD_E_TCPUDPIP;
|
||
|
||
DBGPRINT2(CHL, "NmsChlHdlNamReg: Sending WACK to node with name = (%s) and address = (%X)\n", pNodeToReg->pName, NodeToSendWACKTo.Add.IPAdd);
|
||
|
||
//
|
||
// Send the WACK. Use the explicit NBT dlg handle since the
|
||
// WACK has to be sent as a UDP packet.
|
||
//
|
||
ECommSendMsg(
|
||
&CommExNbtDlgHdl,
|
||
&NodeToSendWACKTo,
|
||
#if USENETBT == 0
|
||
aBuff,
|
||
#else
|
||
aBuff + COMM_NETBT_REM_ADD_SIZE,
|
||
#endif
|
||
BuffLen
|
||
|
||
);
|
||
}
|
||
|
||
WINSMSC_COPY_MEMORY_M(
|
||
pNodeToReg->Name,
|
||
pNodeToReg->pName,
|
||
pNodeToReg->NameLen
|
||
);
|
||
//
|
||
// Insert the request in the challenge queue so that the challenge
|
||
// thread can get it
|
||
//
|
||
RetStat = QueInsertChlReqWrkItm(
|
||
CmdTyp_e,
|
||
Client_e,
|
||
pDlgHdl,
|
||
pMsg,
|
||
MsgLen,
|
||
QuesNamSecLen,
|
||
pNodeToReg,
|
||
pNodeInCnf,
|
||
pAddOfRemWins
|
||
);
|
||
|
||
#ifdef WINSDBG
|
||
if (Client_e == WINS_E_NMSNMH)
|
||
{
|
||
NmsChlNoOfReqNbt++;
|
||
}
|
||
else
|
||
{
|
||
NmsChlNoOfReqRpl++;
|
||
}
|
||
#endif
|
||
DBGLEAVE("NmsChlHdlNamReg\n");
|
||
return(RetStat);
|
||
|
||
} // NmsChlHdlNamReg()
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
ChlThdInitFn(
|
||
IN LPVOID pThreadParam
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This is the initialization function for the name challenge thread
|
||
|
||
|
||
Arguments:
|
||
pThreadParam - NOT USED
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
This function should never return. If it returns it means there
|
||
is some problem. WINS_FAILURE is returned when this happens
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
NmsChlInit
|
||
|
||
Side Effects:
|
||
A name challenge thread is created
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
HANDLE ThdEvtHdlArray[3];
|
||
DWORD ArrInd; //index of hdl signaled
|
||
PCHL_REQ_WRK_ITM_T pWrkItm = NULL;
|
||
BOOL fTablesOpen = FALSE;
|
||
|
||
BOOL bRecoverable = FALSE;
|
||
UNREFERENCED_PARAMETER(pThreadParam);
|
||
|
||
while(TRUE)
|
||
{
|
||
try {
|
||
if (!bRecoverable)
|
||
{
|
||
/*
|
||
|
||
Initialize the thread with the database
|
||
*/
|
||
NmsDbThdInit(WINS_E_NMSCHL);
|
||
DBGMYNAME("Name Challenge Thread");
|
||
|
||
/*
|
||
* Initialize the array of handles on which the challenge thread will
|
||
* wait.
|
||
*/
|
||
ThdEvtHdlArray[0] = NmsTermEvt; //termination event var
|
||
ThdEvtHdlArray[1] = QueNmsNrcqQueHd.EvtHdl; //work queue event var
|
||
ThdEvtHdlArray[2] = QueNmsRrcqQueHd.EvtHdl; //work queue event var
|
||
|
||
bRecoverable = TRUE;
|
||
}
|
||
|
||
while (TRUE)
|
||
{
|
||
|
||
WinsMscWaitUntilSignaled(
|
||
ThdEvtHdlArray,
|
||
sizeof(ThdEvtHdlArray)/sizeof(HANDLE),
|
||
&ArrInd,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// if NmsTermEvt was signaled, terminate self
|
||
//
|
||
if (ArrInd == 0)
|
||
{
|
||
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
|
||
}
|
||
|
||
while (TRUE)
|
||
{
|
||
scPendingRsp = 0; //reinit TransId Counter to 0
|
||
sMaxTransId = 0; //reinit MaxTransId Counter to 0
|
||
RetStat = QueRemoveChlReqWrkItm(
|
||
ThdEvtHdlArray[ArrInd],
|
||
(LPVOID *)spReqWrkItmArr,
|
||
&sMaxTransId
|
||
);
|
||
|
||
if (RetStat == WINS_NO_REQ)
|
||
{
|
||
break; //break out of while loop
|
||
}
|
||
else // one or more items were dequeued
|
||
{
|
||
#ifdef WINSDBG
|
||
NmsChlNoReqDequeued += sMaxTransId;
|
||
#endif
|
||
NmsDbOpenTables(WINS_E_NMSCHL);
|
||
fTablesOpen = TRUE;
|
||
scPendingRsp = sMaxTransId;
|
||
|
||
QueChlWaitForRsp();
|
||
//
|
||
// If HandleWrkItm fails, it will raise
|
||
// an exception
|
||
//
|
||
HandleWrkItm(
|
||
spReqWrkItmArr,
|
||
sMaxTransId,
|
||
FALSE //not a retry
|
||
);
|
||
//
|
||
// Wait for responses to all requests sent
|
||
// WaitForRsp() function will return only
|
||
// after all requests are done with
|
||
// as a result of responses having been
|
||
// received for them, they having timed out
|
||
// after the requisite number of retries or
|
||
// a mix of both.
|
||
//
|
||
WaitForRsp();
|
||
|
||
QueChlNoWaitForRsp();
|
||
|
||
NmsDbCloseTables();
|
||
fTablesOpen = FALSE;
|
||
|
||
}
|
||
} // end of while (TRUE)
|
||
} // end of while (TRUE)
|
||
|
||
} // end of try {..}
|
||
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
if (bRecoverable)
|
||
{
|
||
DWORD No;
|
||
DWORD ExcCode = GetExceptionCode();
|
||
DBGPRINTEXC("ChlThdInitFn: Name Challenge Thread");
|
||
//
|
||
// If ExcCode is NBT_ERR, it could mean that the main thread
|
||
// closed the netbt handle.
|
||
//
|
||
if ( ExcCode == WINS_EXC_NBT_ERR)
|
||
{
|
||
if (WinsCnf.State_e == WINSCNF_E_TERMINATING)
|
||
{
|
||
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
|
||
}
|
||
else
|
||
{
|
||
//if ((WinsCnf.State_e != WINSCNF_E_PAUSED) && (!fWinsCnfInitStatePaused))
|
||
{
|
||
WINSEVT_LOG_M(ExcCode, WINS_EVT_CHL_EXC);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
WINSEVT_LOG_M(ExcCode, WINS_EVT_CHL_EXC);
|
||
}
|
||
|
||
if(fTablesOpen)
|
||
{
|
||
NmsDbCloseTables();
|
||
fTablesOpen = FALSE;
|
||
}
|
||
|
||
//
|
||
// For all requests that were never sent, free them
|
||
//
|
||
for (No=0; No < sMaxTransId; No++)
|
||
{
|
||
if (spReqWrkItmArr[No] != NULL)
|
||
{
|
||
if (spReqWrkItmArr[No]->pMsg != NULL)
|
||
{
|
||
ECommFreeBuff(spReqWrkItmArr[No]->pMsg);
|
||
}
|
||
QueDeallocWrkItm(NmsChlHeapHdl, spReqWrkItmArr[No]);
|
||
}
|
||
}
|
||
|
||
QueChlNoWaitForRsp();
|
||
|
||
} // end of if (bRecoverable)
|
||
else // if (bRecoverable)
|
||
{
|
||
DBGPRINTEXC("ChlThdInitFn: Name Challenge Thread");
|
||
//
|
||
// If NmsDbThdInit comes back with an exception, it is possible
|
||
// that the session has not yet been started. Passing
|
||
// WINS_DB_SESSION_EXISTS however is ok
|
||
//
|
||
//
|
||
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_CHL_ABNORMAL_SHUTDOWN);
|
||
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
|
||
} // if (bRecoverable)
|
||
} // exception handler
|
||
} // while(TRUE)
|
||
//
|
||
// We should never get here
|
||
//
|
||
return(WINS_FAILURE);
|
||
|
||
} // ChlThdInitFn()
|
||
|
||
|
||
|
||
STATUS
|
||
HandleWrkItm(
|
||
IN PCHL_REQ_WRK_ITM_T *ppaWrkItm,
|
||
IN DWORD MaxTransId,
|
||
IN BOOL fRetry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function is called to send a name query to the node that
|
||
was confliciting
|
||
|
||
|
||
Arguments:
|
||
ppaWrkItm - Address of an array of pointers to work items that
|
||
got queued in one or more of the challenge queues
|
||
|
||
MaxTransId - One more than the index of the last filled entry in
|
||
the array
|
||
|
||
fRetry - indicates whether HandleWrkItm is being called to
|
||
retry a request
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes -- WINS_SUCCESS
|
||
Error status codes -- WINS_FAILURE
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
ChlThdInitFn(), WaitForRsp
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
#if USENETBT == 0
|
||
BYTE Buff[COMM_DATAGRAM_SIZE];
|
||
#else
|
||
BYTE Buff[COMM_DATAGRAM_SIZE + COMM_NETBT_REM_ADD_SIZE];
|
||
#endif
|
||
MSG_LEN_T MsgLen;
|
||
LPBYTE pName = NULL;
|
||
DWORD NameLen = 0;
|
||
PCOMM_ADD_T pAddOfNodeInCnf = NULL;
|
||
NMSCHL_CMD_TYP_E CmdTyp_e;
|
||
NMSMSGF_NODE_TYP_E NodeTyp_e;
|
||
DWORD cPendingRsp = 0; //count of pending
|
||
//responses
|
||
volatile DWORD i;
|
||
|
||
DBGENTER("HandleWrkItm\n");
|
||
|
||
PERF("For retries, reuse the buffer sent for the initial try. This means")
|
||
PERF("that I need to allocate it and store it in the request work item")
|
||
PERF("instead of using the stack for it")
|
||
UNREFERENCED_PARAMETER(fRetry);
|
||
|
||
//
|
||
// Loop over all slots of the array that were filled as a result of
|
||
// the acquisition of requests from the challenge request queue(s)
|
||
//
|
||
FUTURES("Remove the exception handler out of production code")
|
||
try {
|
||
DBGPRINT1(CHL, "HandleWrkItm: Max Trans. Id = (%d)\n", MaxTransId);
|
||
for(
|
||
i = 0;
|
||
i < MaxTransId;
|
||
ppaWrkItm++, i++
|
||
)
|
||
{
|
||
//
|
||
// if we have hit an empty slot, it means that this function
|
||
// has been called to retry one or more requests that
|
||
// did not get satisfied in the first wait period. The empty
|
||
// slot indicates that a request that occupied this slot
|
||
// got satisfied in one of the earlier retries. Just
|
||
// skip the empty slot
|
||
//
|
||
if (fRetry && (*ppaWrkItm == NULL))
|
||
{
|
||
DBGPRINT1(CHL, "HandleWrkItm: HIT a NULL entry. Trans. Id = (%d)\n", i);
|
||
continue;
|
||
}
|
||
|
||
(*ppaWrkItm)->NodeToReg.pName = (*ppaWrkItm)->NodeToReg.Name;
|
||
|
||
CmdTyp_e = (*ppaWrkItm)->CmdTyp_e;
|
||
NodeTyp_e = (*ppaWrkItm)->NodeToReg.NodeTyp;
|
||
|
||
pName = (*ppaWrkItm)->NodeToReg.pName;
|
||
|
||
//
|
||
// if the first character is 0x1B, swap the bytes
|
||
// This is for supporting the browser. See
|
||
// NmsMsgfProcNbtReq
|
||
//
|
||
if (*pName == 0x1B)
|
||
{
|
||
WINS_SWAP_BYTES_M(pName, pName + 15);
|
||
}
|
||
NameLen = (*ppaWrkItm)->NodeToReg.NameLen;
|
||
|
||
|
||
//
|
||
// get the last address (the only address unless the node in
|
||
// conflict is a multihomed node) from the list of addresses
|
||
//
|
||
pAddOfNodeInCnf = &((*ppaWrkItm)->NodeAddsInCnf.Mem[
|
||
(*ppaWrkItm)->NoOfAddsToUse - 1
|
||
].Add);
|
||
|
||
|
||
|
||
//
|
||
// If the command is directing us to do a challenge, send a
|
||
// name query
|
||
//
|
||
if (
|
||
(CmdTyp_e == NMSCHL_E_CHL)
|
||
||
|
||
(CmdTyp_e == NMSCHL_E_CHL_N_REL_N_INF)
|
||
||
|
||
(CmdTyp_e == NMSCHL_E_CHL_N_REL)
|
||
)
|
||
{
|
||
DBGPRINT3(CHL, "HandleWrkItm: Sending Name Query Request with Transid = (%d) to node with name = (%s) and address = (%X)\n", i, pName, pAddOfNodeInCnf->Add.IPAdd);
|
||
|
||
NmsMsgfFrmNamQueryReq(
|
||
i, //Transaction Id
|
||
#if USENETBT == 0
|
||
Buff,
|
||
#else
|
||
Buff + COMM_NETBT_REM_ADD_SIZE,
|
||
#endif
|
||
&MsgLen,
|
||
pName,
|
||
NameLen
|
||
);
|
||
|
||
(*ppaWrkItm)->ReqTyp_e = NMSMSGF_E_NAM_QUERY;
|
||
}
|
||
else // has to be NMSCHL_E_REL or NMSCHL_E_REL_N_INF or
|
||
// NMSCHL_E_REL_ONLY
|
||
{
|
||
|
||
DBGPRINT3(CHL,
|
||
"HandleWrkItm: Sending Name Release Request with Transid = (%d) to node with name = (%s) and address = (%X)\n", i, pName, pAddOfNodeInCnf->Add.IPAdd);
|
||
|
||
NmsMsgfFrmNamRelReq(
|
||
i, //Transaction Id
|
||
#if USENETBT == 0
|
||
Buff,
|
||
#else
|
||
Buff + COMM_NETBT_REM_ADD_SIZE,
|
||
#endif
|
||
&MsgLen,
|
||
pName,
|
||
NameLen,
|
||
NodeTyp_e,
|
||
pAddOfNodeInCnf
|
||
);
|
||
(*ppaWrkItm)->ReqTyp_e = NMSMSGF_E_NAM_REL;
|
||
}
|
||
|
||
ECommSendMsg(
|
||
&CommExNbtDlgHdl,
|
||
pAddOfNodeInCnf,
|
||
#if USENETBT == 0
|
||
Buff,
|
||
#else
|
||
Buff + COMM_NETBT_REM_ADD_SIZE,
|
||
#endif
|
||
MsgLen
|
||
);
|
||
cPendingRsp++;
|
||
}
|
||
|
||
//
|
||
// Do a sanity check
|
||
//
|
||
#ifdef WINSDBG
|
||
if (cPendingRsp != scPendingRsp)
|
||
{
|
||
DBGPRINT2(EXC, "SOFTWARE ERROR. THE COUNT OF PENDING RESPONSES (%d) AS COMPUTED BY THE HandleWrkItm FN DOES NOT MATCH WITH THE EXPECTED ONE (%d)\n\n", cPendingRsp, scPendingRsp);
|
||
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
||
}
|
||
#endif
|
||
}
|
||
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
DBGPRINTEXC("HandleWrkItm");
|
||
|
||
//
|
||
// if the exception is an nbt error, it is expected if wins is in
|
||
// the paused state. Do not reraise the exception if this is the
|
||
// case. We want to go through our WaitRsp() function so that
|
||
// the new records (replicas or registrations) get registered.
|
||
// If this results in an inconsistent db, it will straighten
|
||
// itself out soon after WINS is unpaused.
|
||
//
|
||
//if (!((GetExceptionCode() == WINS_EXC_NBT_ERR) && (WinsCnf.State_e ==
|
||
// WINSCNF_E_PAUSED) || (fWinsCnfInitStatePaused)))
|
||
{
|
||
WINS_RERAISE_EXC_M();
|
||
}
|
||
#if 0
|
||
else
|
||
{
|
||
//
|
||
// For all requests that were never sent, free them
|
||
//
|
||
for (No=0; No < sMaxTransId; No++, pReqWrkItm++)
|
||
{
|
||
if (pReqWrkItm != NULL)
|
||
{
|
||
if (pReqWrkItm->pMsg != NULL)
|
||
{
|
||
ECommFreeBuff(pReqWrkItm->pMsg);
|
||
}
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
|
||
|
||
}
|
||
}
|
||
#endif
|
||
} // end of except { .. }
|
||
|
||
DBGLEAVE("HandleWrkItm\n");
|
||
return(WINS_SUCCESS);
|
||
|
||
} // HandleWrkItm()
|
||
|
||
|
||
|
||
|
||
STATUS
|
||
WaitForRsp(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function is responsible for waiting for responses to all
|
||
requests that have been sent until either they time out or their
|
||
responses are received.
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
Return Value:
|
||
WINS_SUCCESS or a failure code. The function can also raise an
|
||
exception in case of fatal errors
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
HANDLE ThdEvtHdlArray[2];
|
||
DWORD Count = 0;
|
||
DWORD TickCntSv;
|
||
DWORD TickCnt = 0;
|
||
DWORD TimeLeft;
|
||
BOOL fSignaled = TRUE; //was an event signaled
|
||
DWORD ArrInd = 0; //Not used
|
||
DWORD i = 0;
|
||
NMSMSGF_ERR_CODE_E Rcode_e = NMSMSGF_E_SRV_ERR;
|
||
PCHL_REQ_WRK_ITM_T pReqWrkItm;
|
||
NMSMSGF_RSP_INFO_T RspInfo;
|
||
BOOL fNewTry = TRUE;
|
||
|
||
/*
|
||
* Initialize the array of handles on which the challenge thread will
|
||
* wait.
|
||
*/
|
||
ThdEvtHdlArray[0] = NmsTermEvt; //termination event var
|
||
ThdEvtHdlArray[1] = QueNmsCrqQueHd.EvtHdl; //work queue event var
|
||
|
||
FUTURES("Remove the try out of production level code")
|
||
try {
|
||
while(TRUE)
|
||
{
|
||
if (fNewTry)
|
||
{
|
||
//
|
||
// Get the number of msecs that have
|
||
// elapsed since windows was started
|
||
//
|
||
TickCntSv = GetTickCount();
|
||
TimeLeft = (1 << Count) * WinsCnf.RetryInterval;
|
||
}
|
||
|
||
//
|
||
// Check if we have exhausted all retries for this batch of
|
||
// requests
|
||
//
|
||
if (Count == WinsCnf.MaxNoOfRetries)
|
||
{
|
||
|
||
//
|
||
// CleanUp all spReqWrkItmArr entries which have not
|
||
// been satisfied as yet.
|
||
//
|
||
for (i = 0; i < sMaxTransId; i++)
|
||
{
|
||
if (spReqWrkItmArr[i] != NULL)
|
||
{
|
||
#ifdef WINSDBG
|
||
NmsChlNoNoRsp++;
|
||
#endif
|
||
pReqWrkItm = spReqWrkItmArr[i];
|
||
|
||
//
|
||
// Decrement the count of addresses to send query or
|
||
// release to.
|
||
//
|
||
pReqWrkItm->NoOfAddsToUse--;
|
||
|
||
//
|
||
//
|
||
// If there are no more addresses to challenge/release
|
||
//
|
||
if (pReqWrkItm->NoOfAddsToUse == 0)
|
||
{
|
||
|
||
//
|
||
// Just in case the record to register is a UNIQUE
|
||
// record. No need to have an if (will add overhead)
|
||
//
|
||
pReqWrkItm->NodeToReg.pNodeAdd =
|
||
&pReqWrkItm->AddToReg;
|
||
//
|
||
// In case the row we are putting in the database is
|
||
// one given to use by the Replicator, we don't
|
||
// need to set Rcode_e. However, to avoid an if
|
||
// test, we just set it. It will remain unused
|
||
//
|
||
if (pReqWrkItm->CmdTyp_e != NMSCHL_E_REL_ONLY)
|
||
{
|
||
if (
|
||
ChlUpdateDb(
|
||
FALSE,
|
||
pReqWrkItm->Client_e,
|
||
&pReqWrkItm->NodeToReg,
|
||
pReqWrkItm->OwnerIdInCnf,
|
||
FALSE //not just a refresh
|
||
) == WINS_SUCCESS
|
||
)
|
||
|
||
{
|
||
DBGPRINT0(CHL, "WaitForRsp:Database Updated\n");
|
||
//
|
||
// if the remote WINS has to be notified of
|
||
// the update, do so
|
||
//
|
||
if(pReqWrkItm->CmdTyp_e ==
|
||
NMSCHL_E_REL_N_INF)
|
||
{
|
||
InfRemWins(pReqWrkItm);
|
||
|
||
}
|
||
Rcode_e = NMSMSGF_E_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
Rcode_e = NMSMSGF_E_SRV_ERR;
|
||
WINSEVT_LOG_M(
|
||
WINS_FAILURE,
|
||
WINS_EVT_CHLSND_REG_RSP_ERR
|
||
);
|
||
|
||
DBGPRINT0(CHL, "WaitForRsp:Server Error\n");
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send a response only if the registration request
|
||
// was sent by an NBT node
|
||
//
|
||
if (
|
||
(pReqWrkItm->Client_e == WINS_E_NMSNMH)
|
||
&&
|
||
(!pReqWrkItm->NodeToReg.fStatic)
|
||
&&
|
||
(!pReqWrkItm->NodeToReg.fAdmin)
|
||
)
|
||
{
|
||
RspInfo.pMsg = pReqWrkItm->pMsg;
|
||
RspInfo.MsgLen = pReqWrkItm->MsgLen;
|
||
RspInfo.QuesNamSecLen =
|
||
pReqWrkItm->QuesNamSecLen;
|
||
RspInfo.Rcode_e = Rcode_e;
|
||
|
||
if (Rcode_e == NMSMSGF_E_SUCCESS)
|
||
{
|
||
EnterCriticalSection(&WinsCnfCnfCrtSec);
|
||
RspInfo.RefreshInterval =
|
||
WinsCnf.RefreshInterval;
|
||
LeaveCriticalSection(&WinsCnfCnfCrtSec);
|
||
}
|
||
|
||
|
||
NmsNmhSndNamRegRsp(
|
||
&pReqWrkItm->DlgHdl,
|
||
&RspInfo
|
||
);
|
||
}
|
||
|
||
//
|
||
// deallocate the req wrk items
|
||
//
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
|
||
|
||
}
|
||
else // we haven't yet dealt with all the addresses. So,
|
||
// let us requeue the work item.
|
||
{
|
||
|
||
//
|
||
// Reinsert the work item since there are other
|
||
// addresses that we need to handle in HandleWrkItm()
|
||
//
|
||
DBGPRINT2(CHL, "WaitForRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
|
||
QueInsertWrkItmAtHdOfList(
|
||
&pReqWrkItm->Head,
|
||
pReqWrkItm->QueTyp_e,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Reinit the array entry to obliterate the
|
||
// possibility of error (see ProcRsp)
|
||
//
|
||
spReqWrkItmArr[i] = NULL;
|
||
scPendingRsp--; //actually there is no need for this
|
||
//since scPendingRsp will be inited
|
||
//after dequeing requests
|
||
|
||
} // end of if
|
||
} //end of for loop for looping over sReqWrkItm array
|
||
|
||
break; //break out of the while(TRUE) loop
|
||
|
||
}
|
||
else //count is != WinsCnf.MaxNoOfRetries
|
||
{
|
||
|
||
WinsMscWaitTimedUntilSignaled(
|
||
ThdEvtHdlArray,
|
||
sizeof(ThdEvtHdlArray)/sizeof(HANDLE),
|
||
&ArrInd,
|
||
TimeLeft,
|
||
&fSignaled
|
||
);
|
||
|
||
//
|
||
// if signaled, it means a response item is in the response
|
||
// queue.
|
||
//
|
||
if (fSignaled)
|
||
{
|
||
|
||
DWORD TicksToSub;
|
||
|
||
//
|
||
// If signaled for termination, do it
|
||
//
|
||
if (ArrInd == 0)
|
||
{
|
||
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
|
||
}
|
||
|
||
DBGPRINT0(CHL, "WaitForRsp: Received a response\n");
|
||
#ifdef WINSDBG
|
||
NmsChlNoRspDequeued++;
|
||
#endif
|
||
ProcRsp();
|
||
|
||
|
||
//
|
||
// If no responses are expected, break out of loop
|
||
//
|
||
if (scPendingRsp == 0)
|
||
{
|
||
break; //break out of the while loop
|
||
}
|
||
|
||
//
|
||
// Get the number of msecs that have
|
||
// elapsed since windows was started
|
||
//
|
||
TickCnt = GetTickCount();
|
||
|
||
//
|
||
// If there has been a wrap around (will happen every 49.7
|
||
// days of Windows being up
|
||
//
|
||
if (TickCnt < TickCntSv)
|
||
{
|
||
TicksToSub = (TickCnt + (MAXULONG - TickCntSv));
|
||
|
||
}
|
||
else
|
||
{
|
||
TicksToSub = TickCnt - TickCntSv;
|
||
}
|
||
|
||
//
|
||
// We don't want to subtract a biger number from a
|
||
// smaller number. This will result in a huge value for
|
||
// TimeLeft making the challenge thread block forever.
|
||
//
|
||
if (TimeLeft > TicksToSub)
|
||
{
|
||
TimeLeft -= TicksToSub;
|
||
fNewTry = FALSE;
|
||
}
|
||
else
|
||
{
|
||
Count++; //increment the count of retries
|
||
if ( Count != WinsCnf.MaxNoOfRetries)
|
||
{
|
||
//
|
||
// The Retry time interval being over, let us
|
||
// retry all those requests that did not get
|
||
// satisfied (i.e. no responses yet)
|
||
//
|
||
HandleWrkItm(
|
||
spReqWrkItmArr,
|
||
sMaxTransId,
|
||
TRUE //it is a retry
|
||
);
|
||
//
|
||
// We have waited for the entire allowed
|
||
// wait time. Time to do a retry
|
||
//
|
||
fNewTry = TRUE;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Count++; //increment the count of retries
|
||
if ( Count != WinsCnf.MaxNoOfRetries)
|
||
{
|
||
//
|
||
// The Retry time interval being over, let us
|
||
// retry all those requests that did not get
|
||
// satisfied (i.e. no responses yet)
|
||
//
|
||
HandleWrkItm(
|
||
spReqWrkItmArr,
|
||
sMaxTransId,
|
||
TRUE //it is a retry
|
||
);
|
||
fNewTry = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
} // end of while (TRUE)
|
||
} // end of try ..
|
||
except(EXCEPTION_EXECUTE_HANDLER) {
|
||
DBGPRINTEXC("WaitForRsp");
|
||
|
||
//
|
||
// must be some serious error. Reraise the exception
|
||
//
|
||
WINS_RERAISE_EXC_M();
|
||
|
||
} // end of except { ..}
|
||
return(WINS_SUCCESS);
|
||
|
||
} // WaitForRsp()
|
||
|
||
|
||
STATUS
|
||
ProcRsp(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function is called to process one or more work items
|
||
queued on the challenge response queue.
|
||
|
||
This response can be to name query or name release requests sent
|
||
earlier
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes -- WINS_SUCCESS
|
||
Error status codes -- WINS_FAILURE
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
WaitForRsp()
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
{
|
||
|
||
DWORD TransId = 0;
|
||
NMSMSGF_NAM_REQ_TYP_E Opcode_e = NMSMSGF_E_NAM_QUERY;
|
||
BYTE Name[NMSMSGF_RFC_MAX_NAM_LEN];
|
||
DWORD NameLen;
|
||
// COMM_IP_ADD_T IPAdd;
|
||
NMSMSGF_CNT_ADD_T CntAdd;
|
||
NMSMSGF_ERR_CODE_E Rcode_e;
|
||
PCHL_REQ_WRK_ITM_T pReqWrkItm;
|
||
STATUS RetVal;
|
||
PCHL_RSP_WRK_ITM_T pRspWrkItm;
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
LPBYTE pNameToComp;
|
||
DWORD NameLenUsedInComp;
|
||
BOOL fAdded;
|
||
BOOL fGroup;
|
||
|
||
DBGENTER("ProcRsp\n");
|
||
while (TRUE)
|
||
{
|
||
//dequeue each response and process
|
||
RetVal = QueRemoveChlRspWrkItm(&pRspWrkItm);
|
||
|
||
if (RetVal == WINS_NO_REQ)
|
||
{
|
||
break;
|
||
}
|
||
if (
|
||
NmsMsgfUfmNamRsp(
|
||
pRspWrkItm->pMsg,
|
||
&Opcode_e,
|
||
&TransId,
|
||
Name,
|
||
&NameLen,
|
||
&CntAdd,
|
||
&Rcode_e,
|
||
&fGroup
|
||
) == WINS_FAILURE
|
||
)
|
||
{
|
||
|
||
//
|
||
// Throw away response
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
#ifdef WINSDBG
|
||
NmsChlNoInvRsp++;
|
||
#endif
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Get the request corresponding to the response.
|
||
//
|
||
if (TransId >= sMaxTransId)
|
||
{
|
||
//
|
||
// Throw away response
|
||
//
|
||
DBGPRINT3(ERR, "ProcRsp: Rsp: Name = (%s); Transid = (%d), Opcode_e = (%d). Being rejected (TOO LARGE TRANS. ID)\n", Name, TransId, Opcode_e);
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
#ifdef WINSDBG
|
||
NmsChlNoInvRsp++;
|
||
#endif
|
||
continue;
|
||
|
||
|
||
}
|
||
pReqWrkItm = spReqWrkItmArr[TransId];
|
||
if (!pReqWrkItm)
|
||
{
|
||
//
|
||
// Throw this response away
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
#ifdef WINSDBG
|
||
NmsChlNoInvRsp++;
|
||
#endif
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// First and foremost check whether the response is for one of
|
||
// the current requests (we want to guard against mismatching
|
||
// the response to a request (the response could be for an old
|
||
// request that is no longer in our spReqWrkItmArr array.
|
||
//
|
||
|
||
|
||
//
|
||
// Compare the Name and the Opcode from where the
|
||
// response came with the same in the request
|
||
//
|
||
pNameToComp = pReqWrkItm->NodeToReg.pName;
|
||
NameLenUsedInComp = pReqWrkItm->NodeToReg.NameLen;
|
||
|
||
RetVal = (ULONG) WINSMSC_COMPARE_MEMORY_M(
|
||
Name,
|
||
pNameToComp,
|
||
NameLenUsedInComp
|
||
);
|
||
if (
|
||
(RetVal != NameLenUsedInComp )
|
||
||
|
||
( pReqWrkItm->ReqTyp_e != Opcode_e )
|
||
)
|
||
{
|
||
//
|
||
// Throw this response away
|
||
//
|
||
DBGPRINT5(ERR, "ProcRsp: Mismatch between response and request. Req/Res Name (%s/%s); ReqType_e/Opcode_e = (%d/%d). TransId = (%d)\n", pNameToComp, Name, pReqWrkItm->ReqTyp_e, Opcode_e, TransId);
|
||
WINSEVT_LOG_INFO_D_M(
|
||
WINS_SUCCESS,
|
||
WINS_EVT_REQ_RSP_MISMATCH
|
||
);
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
#ifdef WINSDBG
|
||
NmsChlNoInvRsp++;
|
||
#endif
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// We have a valid response
|
||
//
|
||
DBGPRINT3(CHL, "ProcRsp: (%s) Response is for name = (%s); 16th char (%X)\n", Opcode_e == NMSMSGF_E_NAM_REL ? "RELEASE" : "QUERY", Name, Name[15]);
|
||
//
|
||
// Decrement the count of addresses to send query or release
|
||
// to. We send query/release to the next address in the list
|
||
// if we get back a negative response to the current one. This
|
||
// is just for extra safety (in case we have one or more
|
||
// addresses in our list that are no longer valid for the name)
|
||
//
|
||
pReqWrkItm->NoOfAddsToUse--;
|
||
|
||
if (Opcode_e == NMSMSGF_E_NAM_REL)
|
||
{
|
||
|
||
//
|
||
// If there are more addresses for sending the releases
|
||
// to, insert the work item at the head of the queue
|
||
//
|
||
if ( (Rcode_e != NMSMSGF_E_SUCCESS) &&
|
||
(pReqWrkItm->NoOfAddsToUse > 0))
|
||
{
|
||
//
|
||
// The request has been processed. Init its
|
||
// position in the array. Also,
|
||
// decrement scPendingRsp.
|
||
//
|
||
spReqWrkItmArr[TransId] = NULL;
|
||
scPendingRsp--;
|
||
|
||
//
|
||
// Now, we have to send the RELEASE to the next
|
||
// address on the list . This
|
||
// request has to be processed in the same
|
||
// way as all the other requests that are
|
||
// queued on our request queues (i.e. retry
|
||
// a certain number of times using a certain
|
||
// time interval). Since we are in the
|
||
// middle of an execution of a batch of
|
||
// requests, queue this request at the head
|
||
// of the next batch of requests.
|
||
//
|
||
DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
|
||
QueInsertWrkItmAtHdOfList(
|
||
&pReqWrkItm->Head,
|
||
pReqWrkItm->QueTyp_e,
|
||
NULL
|
||
);
|
||
//
|
||
// Throw the response away
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
|
||
//
|
||
// deallocate the response buffer
|
||
//
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
return(WINS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Either the name was released or we have exhausted
|
||
// the list of addresses without getting a positive
|
||
// release response
|
||
//
|
||
|
||
//
|
||
// Update the database. Note: There is no need to
|
||
// check the Rcode_e value since even if the release
|
||
// request failed, we will overwrite the entry
|
||
//
|
||
// A release is sent as a result of a clash during
|
||
// replication only, so a client id. of WINS_E_RPLPULL
|
||
// is correct.
|
||
//
|
||
|
||
if (pReqWrkItm->CmdTyp_e == NMSCHL_E_REL)
|
||
{
|
||
pReqWrkItm->NodeToReg.pNodeAdd =
|
||
&pReqWrkItm->AddToReg;
|
||
if (ChlUpdateDb(
|
||
FALSE,
|
||
WINS_E_RPLPULL,
|
||
&pReqWrkItm->NodeToReg,
|
||
pReqWrkItm->OwnerIdInCnf,
|
||
FALSE //not just a refresh
|
||
) != WINS_SUCCESS
|
||
)
|
||
{
|
||
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
|
||
DBGPRINT0(CHL, "ProcRsp:COULD NOT UPDATE THE DB AFTER A RELEASE \n");
|
||
Rcode_e = NMSMSGF_E_SRV_ERR;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// if the remote WINS has to be notified of
|
||
// the update.
|
||
//
|
||
// NOTE: This code won't be executed.
|
||
//
|
||
if(spReqWrkItmArr[TransId]->CmdTyp_e ==
|
||
NMSCHL_E_REL_N_INF)
|
||
{
|
||
InfRemWins(
|
||
spReqWrkItmArr[TransId]
|
||
);
|
||
}
|
||
Rcode_e = NMSMSGF_E_SUCCESS;
|
||
}
|
||
}
|
||
|
||
}
|
||
else // it is a name query response
|
||
{
|
||
|
||
#ifdef WINSDBG
|
||
{
|
||
DWORD i;
|
||
for (i=0; i<CntAdd.NoOfAdds;i++)
|
||
{
|
||
DBGPRINT2(CHL, "ProcRsp: Address (%d) is (%X)\n", (i+1),CntAdd.Add[i].Add.IPAdd);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// if the challenge succeded, we may need
|
||
// to update the database
|
||
//
|
||
if (Rcode_e != NMSMSGF_E_SUCCESS ||
|
||
pReqWrkItm->fGroupInCnf != fGroup)
|
||
{
|
||
|
||
//
|
||
// a negative name query response was received
|
||
// OR Record type (unique vs group) doesn't match
|
||
// (the second check is to consider the case of
|
||
// a node which used the same name first as unique
|
||
// and then as group)
|
||
//
|
||
|
||
//
|
||
// If there are no more addresses to query
|
||
//
|
||
if (pReqWrkItm->NoOfAddsToUse == 0)
|
||
{
|
||
//
|
||
// Update the database
|
||
//
|
||
pReqWrkItm->NodeToReg.pNodeAdd =
|
||
&pReqWrkItm->AddToReg;
|
||
if (ChlUpdateDb(
|
||
FALSE,
|
||
pReqWrkItm->Client_e,
|
||
&pReqWrkItm->NodeToReg,
|
||
pReqWrkItm->OwnerIdInCnf,
|
||
FALSE
|
||
) == WINS_SUCCESS
|
||
)
|
||
{
|
||
|
||
//
|
||
// Set Rcode_e to SUCCESS
|
||
//
|
||
Rcode_e = NMSMSGF_E_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
Rcode_e = NMSMSGF_E_SRV_ERR;
|
||
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We need to challenge (query) the next
|
||
// address in the list of addresses
|
||
//
|
||
spReqWrkItmArr[TransId] = NULL;
|
||
scPendingRsp--;
|
||
|
||
DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d)\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
|
||
QueInsertWrkItmAtHdOfList(
|
||
&pReqWrkItm->Head,
|
||
pReqWrkItm->QueTyp_e,
|
||
NULL
|
||
);
|
||
//
|
||
// Throw this response away
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
|
||
//
|
||
// deallocate the response buffer
|
||
//
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
return(WINS_SUCCESS);
|
||
}
|
||
}
|
||
else // positive name query response received
|
||
{
|
||
|
||
//
|
||
// if the cmd is CHL_N_REL, we need to now tell
|
||
// the remote node to release the name.
|
||
//
|
||
|
||
if (CntAdd.NoOfAdds == 1)
|
||
{
|
||
//
|
||
// Note: the CmdType_e will be CHL_N_REL
|
||
// only if the client is WINS_E_RPLPULL
|
||
//
|
||
if (pReqWrkItm->CmdTyp_e == NMSCHL_E_CHL_N_REL)
|
||
{
|
||
DWORD No;
|
||
|
||
//
|
||
// We need to tell the remote node
|
||
// release all names.
|
||
//
|
||
pReqWrkItm->CmdTyp_e = NMSCHL_E_REL_ONLY;
|
||
|
||
spReqWrkItmArr[TransId] = NULL;
|
||
scPendingRsp--;
|
||
|
||
//
|
||
// We need to update the Version
|
||
// no of the conflicting entry
|
||
//
|
||
(VOID)ChlUpdateDb(
|
||
TRUE, //update vers. no.
|
||
WINS_E_NMSNMH, //to speed fn up
|
||
&pReqWrkItm->NodeToReg,
|
||
pReqWrkItm->OwnerIdInCnf,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Tell the remote guy to release
|
||
// the name. Copy the addresses of
|
||
// into the proper field
|
||
//
|
||
pReqWrkItm->NoOfAddsToUse =
|
||
pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
|
||
ASSERT(pReqWrkItm->NoOfAddsToUse <= NMSDB_MAX_MEMS_IN_GRP);
|
||
for (No=0; No < pReqWrkItm->NoOfAddsToUse; No++)
|
||
{
|
||
*(pReqWrkItm->NodeAddsInCnf.Mem + No) = *(pReqWrkItm->NodeToReg.NodeAdds.Mem + No);
|
||
|
||
}
|
||
pReqWrkItm->NodeAddsInCnf.NoOfMems
|
||
= pReqWrkItm->NoOfAddsToUse;
|
||
|
||
DBGPRINT2(CHL, "ProcRsp: Name = (%s); NoOfAddsToUse is (%d); request REL_ONLY\n", pReqWrkItm->NodeToReg.Name, pReqWrkItm->NoOfAddsToUse);
|
||
QueInsertWrkItmAtHdOfList(
|
||
&pReqWrkItm->Head,
|
||
pReqWrkItm->QueTyp_e,
|
||
NULL
|
||
);
|
||
//
|
||
// Throw this response away
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
|
||
//
|
||
// deallocate the response buffer
|
||
//
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
return(WINS_SUCCESS);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If more than one address was returned in the
|
||
// query response, it means that the challenged
|
||
// node is a multi-homed node. Actually, a multihomed
|
||
// node could return just one address too. This is
|
||
// because it might have just come up and the name
|
||
// may not have yet been registered for the multiple
|
||
// adapters.
|
||
|
||
//
|
||
// Note: We execute the else code if the
|
||
// record to register is a special group
|
||
//
|
||
if (
|
||
!NMSDB_ENTRY_GRP_M(pReqWrkItm->NodeToReg.EntTyp)
|
||
)
|
||
{
|
||
//
|
||
// Check if we need to update the db
|
||
//
|
||
RetStat = ProcAddList(
|
||
pReqWrkItm,
|
||
&CntAdd,
|
||
&fAdded
|
||
);
|
||
|
||
if (RetStat == WINS_FAILURE)
|
||
{
|
||
//
|
||
// There is atleast one address in the
|
||
// list to register that is not in the
|
||
// list of addresses returned. This means
|
||
// that at least one of the addresses to
|
||
// register is not claimed by the node
|
||
// that responded. We can not honor
|
||
// this registration
|
||
//
|
||
|
||
//
|
||
// NAME ACTIVE error
|
||
//
|
||
Rcode_e = NMSMSGF_E_ACT_ERR;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Update the database
|
||
//
|
||
pReqWrkItm->NodeToReg.pNodeAdd =
|
||
&pReqWrkItm->AddToReg;
|
||
|
||
if (ChlUpdateDb(
|
||
FALSE,
|
||
pReqWrkItm->Client_e,
|
||
&pReqWrkItm->NodeToReg,
|
||
pReqWrkItm->OwnerIdInCnf,
|
||
!fAdded
|
||
) == WINS_SUCCESS
|
||
)
|
||
{
|
||
|
||
//
|
||
// Set Rcode_e to SUCCESS
|
||
//
|
||
Rcode_e = NMSMSGF_E_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
Rcode_e = NMSMSGF_E_SRV_ERR;
|
||
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_CANT_UPDATE_DB);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
CHECK("Should a local multihomed node be told to release the name if it ")
|
||
CHECK("with a replica. This is what is done for the local unique/remote unique")
|
||
CHECK("name clash. It seems the right strategy but may need to be rethought")
|
||
|
||
else // entry to register is a group
|
||
{
|
||
//
|
||
// set Rcode_e to Error code
|
||
//
|
||
Rcode_e = NMSMSGF_E_ACT_ERR;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// The request has been processed. Init its position
|
||
// in the array. Send the response to the waiting node
|
||
// This will free the buffer too.
|
||
//
|
||
// Also, decrement scPendingRsp. This was incremented by
|
||
// HandleWrkItm for each query/release sent.
|
||
//
|
||
spReqWrkItmArr[TransId] = NULL;
|
||
scPendingRsp--;
|
||
|
||
//
|
||
// Send a registration response only if the client that
|
||
// submitted the request was an NBT thread.
|
||
//
|
||
if (
|
||
(pReqWrkItm->Client_e == WINS_E_NMSNMH)
|
||
&&
|
||
(!pReqWrkItm->NodeToReg.fStatic)
|
||
&&
|
||
(!pReqWrkItm->NodeToReg.fAdmin)
|
||
)
|
||
{
|
||
NMSMSGF_RSP_INFO_T RspInfo;
|
||
|
||
RspInfo.pMsg = pReqWrkItm->pMsg;
|
||
RspInfo.MsgLen = pReqWrkItm->MsgLen;
|
||
RspInfo.QuesNamSecLen = pReqWrkItm->QuesNamSecLen;
|
||
RspInfo.Rcode_e = Rcode_e;
|
||
|
||
if (Rcode_e == NMSMSGF_E_SUCCESS)
|
||
{
|
||
EnterCriticalSection(&WinsCnfCnfCrtSec);
|
||
RspInfo.RefreshInterval = WinsCnf.RefreshInterval;
|
||
LeaveCriticalSection(&WinsCnfCnfCrtSec);
|
||
DBGPRINT0(CHL, "ProcRsp: Sending a Positive name registration response\n");
|
||
}
|
||
#ifdef WINSDBG
|
||
else
|
||
{
|
||
DBGPRINT0(CHL, "ProcRsp: Sending a negative name registration response\n");
|
||
}
|
||
#endif
|
||
|
||
NmsNmhSndNamRegRsp(
|
||
&pReqWrkItm->DlgHdl,
|
||
&RspInfo
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Throw this response away
|
||
//
|
||
ECommFreeBuff(pRspWrkItm->pMsg);
|
||
|
||
//
|
||
// deallocate the req and rsp wrk items
|
||
//
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pReqWrkItm);
|
||
QueDeallocWrkItm(NmsChlHeapHdl, pRspWrkItm);
|
||
}
|
||
|
||
DBGLEAVE("ProcRsp\n");
|
||
return(WINS_SUCCESS);
|
||
} // ProcRsp()
|
||
|
||
|
||
|
||
STATUS
|
||
ChlUpdateDb(
|
||
BOOL fUpdVersNoOfCnfRec,
|
||
WINS_CLIENT_E Client_e,
|
||
PNMSDB_ROW_INFO_T pRowInfo,
|
||
DWORD OwnerIdInCnf,
|
||
BOOL fRefreshOnly
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
This function is called to update the database. It is called
|
||
by ProcRsp and by ChlThdInitFn when challenge succeeds
|
||
|
||
Arguments:
|
||
Client_e - id of client that submitted the request
|
||
pRowInfo - info about the record to be inserted
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
|
||
Return Value:
|
||
|
||
Success status codes -- WINS_SUCCESS
|
||
Error status codes -- WINS_FAILURE
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
WaitForRsp(), ProcRsp()
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
|
||
{
|
||
NMSDB_STAT_INFO_T StatInfo;
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
BOOL fIncVersNo = FALSE;
|
||
|
||
DBGENTER("ChlUpdateDb\n");
|
||
|
||
//
|
||
// update the time
|
||
//
|
||
PERF("We can avoid this call to time, since we called time earlier before we")
|
||
PERF("challenge. In the worst case that time will be off by a 2.5-3")
|
||
PERF("unless the thread is preempted for a long time")
|
||
PERF("assuming a name challenge and release took place. In the best case")
|
||
PERF("it will be off by 1.25-1.5 secs (if just a challenge). We can add ")
|
||
PERF("1.25 secs to that time and avoid the overhead of a function call")
|
||
|
||
(void)time(&pRowInfo->TimeStamp);
|
||
|
||
if (((Client_e == WINS_E_NMSNMH) && !fRefreshOnly) ||
|
||
fUpdVersNoOfCnfRec)
|
||
{
|
||
fIncVersNo = TRUE;
|
||
}
|
||
EnterCriticalSection(&NmsNmhNamRegCrtSec);
|
||
if (pRowInfo->OwnerId == NMSDB_LOCAL_OWNER_ID)
|
||
{
|
||
pRowInfo->TimeStamp += WinsCnf.RefreshInterval;
|
||
}
|
||
else
|
||
{
|
||
pRowInfo->TimeStamp += WinsCnf.VerifyInterval;
|
||
}
|
||
try
|
||
{
|
||
|
||
//
|
||
// If the client (the one that submitted the challenge request) is
|
||
// an NBT thread, we need to store the new version number. If the
|
||
// client is the replicator, we use the version number in the
|
||
// record
|
||
//
|
||
if (fIncVersNo)
|
||
{
|
||
pRowInfo->VersNo = NmsNmhMyMaxVersNo;
|
||
}
|
||
|
||
StatInfo.OwnerId = OwnerIdInCnf;
|
||
if (*(pRowInfo->pName+15) == 0x1B)
|
||
{
|
||
WINS_SWAP_BYTES_M(pRowInfo->pName, pRowInfo->pName+15);
|
||
}
|
||
|
||
//
|
||
// If the vers. no of the local record needs to be updated, do so.
|
||
//
|
||
if (fUpdVersNoOfCnfRec)
|
||
{
|
||
RetStat = NmsDbUpdateVersNo (FALSE, pRowInfo, &StatInfo);
|
||
}
|
||
else
|
||
{
|
||
RetStat = NmsDbSeekNUpdateRow(
|
||
pRowInfo,
|
||
&StatInfo
|
||
);
|
||
}
|
||
|
||
if ((RetStat == WINS_SUCCESS) && (StatInfo.StatCode == NMSDB_SUCCESS))
|
||
{
|
||
//
|
||
// If the client is an NBT thread, we increment the version
|
||
// number since the record we inserted in the db is
|
||
// owned by us (we could also check the owner id here). If
|
||
// the client is the replicator thread, we don't do anything
|
||
//
|
||
if (fIncVersNo)
|
||
{
|
||
NMSNMH_INC_VERS_COUNTER_M(
|
||
NmsNmhMyMaxVersNo,
|
||
NmsNmhMyMaxVersNo
|
||
);
|
||
|
||
//
|
||
// if fAddChgTrigger is TRUE, we pass RPL_PUSH_PROP
|
||
// as the first parameter. Its value is TRUE. See
|
||
// rpl.h
|
||
//
|
||
RPL_PUSH_NTF_M(
|
||
(WinsCnf.PushInfo.fAddChgTrigger ? RPL_PUSH_PROP :
|
||
RPL_PUSH_NO_PROP), NULL, NULL, NULL);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT1(ERR, "ChlUpdateDb: Update of record with name (%s) FAILED\n", pRowInfo->pName);
|
||
|
||
RetStat = WINS_FAILURE;
|
||
}
|
||
}
|
||
except (EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
DBGPRINTEXC("ChlUpdateDb")
|
||
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_CANT_UPDATE_DB);
|
||
}
|
||
LeaveCriticalSection(&NmsNmhNamRegCrtSec);
|
||
|
||
DBGLEAVE("ChlUpdateDb\n");
|
||
return (RetStat);
|
||
} //ChlUpdateDb()
|
||
|
||
|
||
VOID
|
||
InfRemWins(
|
||
PCHL_REQ_WRK_ITM_T pWrkItm
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called when a remote WINS has to be
|
||
told to change the version stamp of a record that was
|
||
pulled by the local WINS at replication. The need for this
|
||
has arisen because the pulled record collided with a record
|
||
owned by the local WINS (both records being in the active
|
||
state).
|
||
|
||
|
||
Arguments:
|
||
pWrkItm - the work item that got queued to the name challenge
|
||
manager
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
Return Value:
|
||
None
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
ProcRsp
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
None
|
||
--*/
|
||
{
|
||
COMM_HDL_T DlgHdl;
|
||
BYTE ReqBuff[RPLMSGF_UPDVERSNO_REQ_SIZE];
|
||
LPBYTE pRspBuff;
|
||
DWORD ReqBuffLen;
|
||
DWORD RspBuffLen;
|
||
NMSMSGF_ERR_CODE_E Rcode_e = 0; //init to 0. This is initialization
|
||
//is important since we update
|
||
//the LSB of Rcode_e with the
|
||
//the return status
|
||
|
||
|
||
DBGENTER("InfRemWins\n");
|
||
try {
|
||
|
||
//
|
||
// Log an event since this is an important event to monitor (at
|
||
// least initially)
|
||
//
|
||
NONPORT("Change the following for transport independence")
|
||
WINSEVT_LOG_INFO_D_M(pWrkItm->AddOfRemWins.Add.IPAdd,
|
||
WINS_EVT_INF_REM_WINS);
|
||
|
||
//
|
||
// Start a dialogue to send the update version number request
|
||
//
|
||
|
||
//
|
||
// Init the pEnt field to NULL so that ECommEndDlg (in the
|
||
// exception handler) called as a result of an exception from
|
||
// behaves fine.
|
||
//
|
||
DlgHdl.pEnt = NULL;
|
||
|
||
ECommStartDlg(
|
||
&pWrkItm->AddOfRemWins,
|
||
COMM_E_RPL,
|
||
&DlgHdl
|
||
);
|
||
|
||
|
||
RplMsgfFrmUpdVersNoReq(
|
||
&ReqBuff[COMM_N_TCP_HDR_SZ],
|
||
pWrkItm->NodeToReg.pName,
|
||
pWrkItm->NodeToReg.NameLen,
|
||
&ReqBuffLen
|
||
);
|
||
|
||
|
||
//
|
||
// Send the "Update Version number" request
|
||
//
|
||
ECommSndCmd(
|
||
&DlgHdl,
|
||
&ReqBuff[COMM_N_TCP_HDR_SZ],
|
||
ReqBuffLen,
|
||
&pRspBuff,
|
||
&RspBuffLen
|
||
);
|
||
//
|
||
// decipher the reponse to get the result code sent by the
|
||
// remote WINS
|
||
//
|
||
RplMsgfUfmUpdVersNoRsp(
|
||
pRspBuff + 4, //past the opcode
|
||
(LPBYTE)&Rcode_e
|
||
);
|
||
|
||
if (Rcode_e != NMSMSGF_E_SUCCESS)
|
||
{
|
||
DBGPRINT0(ERR, "Remote WINS could not update the version no. of its record");
|
||
WINSEVT_LOG_M(pWrkItm->AddOfRemWins.Add.IPAdd, WINS_EVT_REM_WINS_CANT_UPD_VERS_NO);
|
||
FUTURES("Take some corrective action -- maybe")
|
||
|
||
}
|
||
|
||
//
|
||
// deallocate the request and response buffers
|
||
//
|
||
#if 0
|
||
WinsMscDealloc(pReqBuff);
|
||
#endif
|
||
ECommFreeBuff(pRspBuff - COMM_HEADER_SIZE);
|
||
|
||
} // end of try block
|
||
|
||
except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
DWORD ExcCode = GetExceptionCode();
|
||
DBGPRINT1(EXC, "InfRemWins: Got exception (%x)\n", ExcCode );
|
||
if (ExcCode == WINS_EXC_COMM_FAIL)
|
||
{
|
||
DBGPRINT1(ERR, "InfRemWins: Could not inform WINS (%x) that it should update the version number for a record", pWrkItm->AddOfRemWins.Add.IPAdd);
|
||
//
|
||
//insert a timer request for retrying
|
||
//
|
||
|
||
FUTURES("Incorporate code to insert a timer request so that we can retry")
|
||
}
|
||
else
|
||
{
|
||
//severe error.
|
||
DBGPRINT0(ERR, "InfRemWins: Some severe error was encountered\n");
|
||
}
|
||
WINSEVT_LOG_M(ExcCode, WINS_EVT_INF_REM_WINS_EXC);
|
||
}
|
||
//
|
||
// End the dialogue
|
||
//
|
||
ECommEndDlg( &DlgHdl );
|
||
|
||
DBGLEAVE("InfRemWins\n");
|
||
return;
|
||
|
||
} // InfRemWins()
|
||
|
||
|
||
STATUS
|
||
ProcAddList(
|
||
PCHL_REQ_WRK_ITM_T pReqWrkItm,
|
||
PNMSMSGF_CNT_ADD_T pCntAdd,
|
||
LPBOOL pfAdded
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
pWrkItm - the work item that got queued to the name challenge
|
||
manager
|
||
pCntAdd - List of addresses returned on a query
|
||
|
||
Externals Used:
|
||
None
|
||
|
||
Return Value:
|
||
None
|
||
|
||
Error Handling:
|
||
|
||
Called by:
|
||
|
||
ProcRsp
|
||
|
||
Side Effects:
|
||
|
||
Comments:
|
||
The function will never be called when the state
|
||
of the entry to register is a TOMBSTONE or if the entry to register
|
||
is a group.
|
||
|
||
--*/
|
||
{
|
||
DWORD i, n;
|
||
DWORD NoOfAddsToReg;
|
||
STATUS RetStat = WINS_SUCCESS;
|
||
PNMSDB_GRP_MEM_ENTRY_T pMem;
|
||
PCOMM_ADD_T pAddInRsp;
|
||
|
||
DBGENTER("ProcAddList\n");
|
||
*pfAdded = FALSE; //no address of conflicting entry has yet been
|
||
//added to list of addresses of record to register
|
||
|
||
//
|
||
// If the node to register is a unique record
|
||
//
|
||
if (pReqWrkItm->NodeToReg.EntTyp == NMSDB_UNIQUE_ENTRY)
|
||
{
|
||
NoOfAddsToReg = 1;
|
||
pReqWrkItm->NodeToReg.NodeAdds.Mem[0].Add =
|
||
pReqWrkItm->AddToReg;
|
||
pReqWrkItm->NodeToReg.NodeAdds.Mem[0].OwnerId =
|
||
pReqWrkItm->NodeToReg.OwnerId;
|
||
pReqWrkItm->NodeToReg.NodeAdds.Mem[0].TimeStamp =
|
||
pReqWrkItm->NodeToReg.TimeStamp;
|
||
pReqWrkItm->NodeToReg.NodeAdds.NoOfMems = 1;
|
||
|
||
}
|
||
else // has to be multihomed (see comment above)
|
||
{
|
||
NoOfAddsToReg = pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
|
||
|
||
//
|
||
// The addresses are already there in NodeToReg.NodeAdds structure
|
||
//
|
||
|
||
}
|
||
|
||
//
|
||
// If the address(es) to register are not a subset of the addresses
|
||
// returned (i.e. atleast one address to register is not there in
|
||
// the list returned), we return FAILURE.
|
||
//
|
||
|
||
//
|
||
// Loop over all addresses to register
|
||
//
|
||
for (i=0; i < NoOfAddsToReg; i++)
|
||
{
|
||
//
|
||
// Compare with each address returned to see if there is
|
||
// a match. Note: pCntAdd->NoOfAdds is > 1 (this function
|
||
// isn't called otherwise).
|
||
//
|
||
for (n=0; n < pCntAdd->NoOfAdds; n++)
|
||
{
|
||
PERF("use pointer arithmetic")
|
||
if (pReqWrkItm->NodeToReg.NodeAdds.Mem[i].Add.Add.IPAdd ==
|
||
pCntAdd->Add[n].Add.IPAdd)
|
||
{
|
||
//
|
||
// There is a match, break out so that we can
|
||
// can get to the next address in the list of
|
||
// addresses to register
|
||
//
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if there was no match, we have an address to register that
|
||
// either the queried (challenged) node does not have or refuses
|
||
// to divulge to us. We must reject the registration/refresh
|
||
//
|
||
if (n == pCntAdd->NoOfAdds)
|
||
{
|
||
RetStat = WINS_FAILURE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// The address(es) to register are a subset of the addresses returned
|
||
// by the node (on a query)
|
||
//
|
||
if ( RetStat == WINS_SUCCESS)
|
||
{
|
||
DWORD Index;
|
||
|
||
//
|
||
// Remove those members in the conflicting record that are
|
||
// not in the list returned by the node
|
||
//
|
||
for (
|
||
i=0, pMem = pReqWrkItm->NodeAddsInCnf.Mem;
|
||
i < min(pReqWrkItm->NodeAddsInCnf.NoOfMems,
|
||
NMSMSGF_MAX_NO_MULTIH_ADDS);
|
||
i++, pMem++
|
||
)
|
||
{
|
||
pAddInRsp = pCntAdd->Add;
|
||
for (n=0; n < pCntAdd->NoOfAdds; n++, pAddInRsp++)
|
||
{
|
||
PERF("use pointer arithmetic")
|
||
if (pMem->Add.Add.IPAdd == pAddInRsp->Add.IPAdd)
|
||
{
|
||
//
|
||
// There is a match, break out so that we can
|
||
// can get to the next address in the list of
|
||
// addresses in the conflicting record
|
||
//
|
||
break;
|
||
}
|
||
}
|
||
if (n == pCntAdd->NoOfAdds)
|
||
{
|
||
//
|
||
// remove the conflicting member from the list
|
||
// This is done by setting its address to NONE. Later
|
||
// on, we simply won't add this address.
|
||
//
|
||
DBGPRINT3(CHL, "ProcAddList: Removing member (%x) from list of name = (%s)[%x]\n", pMem->Add.Add.IPAdd, pReqWrkItm->NodeToReg.Name, pReqWrkItm->NodeToReg.Name[15]);
|
||
pMem->Add.Add.IPAdd = INADDR_NONE;
|
||
|
||
}
|
||
}
|
||
|
||
DBGPRINT0(CHL, "ProcAddList: Add conflicting record members\n");
|
||
|
||
//
|
||
// The record in conflict has to be ACTIVE
|
||
// (otherwise this function wouldn't have been called -- See
|
||
// the clash functions in nmsnmh.c). We add all those addresses
|
||
// in the active conflicting record to the list of addresses in
|
||
// the record to register that are not there in it already
|
||
//
|
||
|
||
//
|
||
// Add to list of addresses to register all the addresses in
|
||
// the conflicting record. Note: The conflicting record
|
||
// will not have any address in common with the record
|
||
// to register (common addresses were removed in the clash
|
||
// handling functions of nmsnmh.c via MemInGrp())
|
||
//
|
||
|
||
//
|
||
// NOTE: the NoOfMems of the NodeAddsInCnf field is guaranteed
|
||
// to be > 0
|
||
//
|
||
//
|
||
// Also NOTE: If the challenged node returned us a list > 25 members
|
||
// long and our list of members to register can no accommodate
|
||
// all the members that need to be added, we will just add those
|
||
// that can be added without violating the NMSMSGF_MAX_NO_MULTIH_ADDS
|
||
// constraint. The members added could be 0 if we already have
|
||
// the first 25 in our list. Neverthless we will update our
|
||
// db entry. This is because some of the conflicting record's
|
||
// members may be old. They will get removed this way (we don't
|
||
// compare the list returned by the challenged node with what is
|
||
// in the conflicting record currently, so old entries will be
|
||
// there until they are scavenged or fall off).
|
||
//
|
||
Index = pReqWrkItm->NodeToReg.NodeAdds.NoOfMems;
|
||
pMem = pReqWrkItm->NodeAddsInCnf.Mem;
|
||
for ( i=0;
|
||
i < min(pReqWrkItm->NodeAddsInCnf.NoOfMems,
|
||
(NMSMSGF_MAX_NO_MULTIH_ADDS - Index));
|
||
i++, pMem++
|
||
)
|
||
{
|
||
//
|
||
// we need to add the conflicting record's
|
||
// address into the registering record's
|
||
// list of addresses
|
||
//
|
||
if (pMem->Add.Add.IPAdd != INADDR_NONE)
|
||
{
|
||
pReqWrkItm->NodeToReg.NodeAdds.Mem[
|
||
pReqWrkItm->NodeToReg.NodeAdds.NoOfMems
|
||
] = *pMem;
|
||
pReqWrkItm->NodeToReg.NodeAdds.NoOfMems++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Setting *pfAdded to TRUE will increment the version number.
|
||
// We do want to increment the version number because
|
||
// the reason we are here means one of the following:
|
||
//
|
||
// 1)We got a refresh (unique) for an address not in the
|
||
// conf. rec.
|
||
// 2)We got a registration for an address that is/is not
|
||
// there in the conflicting record.
|
||
//
|
||
// For the first case above, we definitely want to increment
|
||
// the version no. For the second case, it is not strictly
|
||
// required but is preferable for syncing up entries at
|
||
// different WINS servers right away.
|
||
//
|
||
*pfAdded = TRUE;
|
||
|
||
//
|
||
// If the record to register was a unique record
|
||
// change its type to MULTIHOMED.
|
||
//
|
||
if ( NMSDB_ENTRY_UNIQUE_M(pReqWrkItm->NodeToReg.EntTyp) )
|
||
{
|
||
pReqWrkItm->NodeToReg.EntTyp = NMSDB_MULTIHOMED_ENTRY;
|
||
}
|
||
|
||
}
|
||
|
||
DBGLEAVE("ProcAddList\n");
|
||
return(RetStat);
|
||
}
|
||
|
||
|