1971 lines
52 KiB
C
1971 lines
52 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
commapi.c
|
|
|
|
Abstract:
|
|
This module contains the interface functions to interface with
|
|
the comm. subsystem. These functions are used by the Replicator and
|
|
the Name Space Manager.
|
|
|
|
Functions:
|
|
|
|
|
|
Portability:
|
|
|
|
This module is portable
|
|
|
|
Author:
|
|
|
|
Pradeep Bahl (PradeepB) Dec-1992
|
|
|
|
Revision History:
|
|
|
|
Modification date Person Description of modification
|
|
----------------- ------- ----------------------------
|
|
--*/
|
|
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "wins.h"
|
|
#include <winsock2.h>
|
|
#include "nms.h"
|
|
#include "winscnf.h"
|
|
#include "comm.h"
|
|
#include "assoc.h"
|
|
#include "nmsdb.h"
|
|
#include "winsmsc.h"
|
|
#include "winsevt.h"
|
|
#include "rpl.h"
|
|
|
|
/*
|
|
* Local Macro Declarations
|
|
*/
|
|
|
|
|
|
/*
|
|
* Local Typedef Declarations
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* Global Variable Definitions
|
|
*/
|
|
|
|
COMM_HDL_T QservDlgList; //list of Q server dialogues.
|
|
HANDLE CommUdpBuffHeapHdl; //handle to heap used for allocating
|
|
//buffers for storing datagrams
|
|
HANDLE CommUdpDlgHeapHdl; //handle to heap used for allocating
|
|
//dlgs for udp buffers
|
|
|
|
|
|
HANDLE sThdEvtArr[2]; //used by the Push thread in
|
|
//ECommProcessDlg
|
|
|
|
SOCKET CommPnPNotificationSocket = INVALID_SOCKET; //to receive addr change notification
|
|
SOCKET CommTcpPortHandle = INVALID_SOCKET; //stores TCP port (socket) #
|
|
SOCKET CommUdpPortHandle = INVALID_SOCKET; //stores UDP port (socket) #
|
|
SOCKET CommNtfSockHandle = INVALID_SOCKET; //stores socket # of socket used
|
|
//for listening for connection
|
|
//notification messages from another
|
|
//thread in the local WINS)
|
|
struct sockaddr_in CommNtfSockAdd; //stores address bound to
|
|
//connection notification socket
|
|
|
|
|
|
#if SPX > 0
|
|
SOCKET CommSpxPortHandle = INVALID_SOCKET; //stores SPX port (socket) #
|
|
SOCKET CommIpxPortHandle = INVALID_SOCKET; //stores IPX port (socket) #
|
|
SOCKET CommIpxNtfSockHandle = INVALID_SOCKET; //stores socket # of socket used
|
|
//for listening for connection
|
|
//notification messages from another
|
|
//thread in the local WINS)
|
|
|
|
struct sockaddr_ipx CommIpxNtfSockAdd; //stores address bound to
|
|
//connection notification socket
|
|
|
|
#endif
|
|
COMM_HDL_T CommExNbtDlgHdl; /*explicit dialogue (used for
|
|
*sending UDP requests to nbt nodes */
|
|
|
|
//
|
|
// get rid of it when support for rpc function WinsGetNameAndAdd is
|
|
// removed.
|
|
//
|
|
#if USENETBT == 0
|
|
FUTURES("Remove this when support for WinsGetNameOrIpAdd is removed")
|
|
FUTURES("Check out ECommGetMyAdd")
|
|
BYTE HostName[NMSDB_MAX_NAM_LEN];
|
|
#endif
|
|
|
|
/*
|
|
* Local Variable Definitions
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
Externals
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
* Local Function Prototype Declarations
|
|
*/
|
|
VOID
|
|
InitOwnAddTbl(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// function definitions
|
|
//
|
|
DWORD
|
|
CommCreatePnPNotificationSocket(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Registry Error.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Create a socket
|
|
//
|
|
//--ft 06/01/2000: make multiple calls to CommCreatePnPNotificationSocket safe
|
|
//CommCreatePnPNotificationSocket is called from both ECommInit and ECommGetMyAdd
|
|
if (CommPnPNotificationSocket == INVALID_SOCKET)
|
|
{
|
|
CommPnPNotificationSocket = socket(
|
|
PF_INET,
|
|
SOCK_DGRAM,
|
|
IPPROTO_UDP );
|
|
|
|
if ( CommPnPNotificationSocket == INVALID_SOCKET ) {
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1( ERR,"could not create PnP notification socket, %ld.\n", Error );
|
|
}
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
VOID
|
|
CommInterfaceChangeNotification(
|
|
DWORD Error,
|
|
DWORD cbTransferred,
|
|
LPWSAOVERLAPPED lpOverlapped,
|
|
DWORD dwFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
Registry Error.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT1(FLOW, "CommInterfaceChangeNotification with Error value = (%x)\n", Error);
|
|
if ( Error == ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// reregister intrface change notification before we process
|
|
// the current list change. This is required to avoid misssing
|
|
// any interface changes that occur while we are processing
|
|
// the current list.
|
|
ECommRegisterAddrChange();
|
|
|
|
if (ECommGetMyAdd(&NmsLocalAdd) == WINS_SUCCESS)
|
|
{
|
|
|
|
WinsEvtLogDetEvt(
|
|
TRUE,
|
|
WINS_PNP_ADDR_CHANGED,
|
|
NULL,
|
|
__LINE__,
|
|
"dd",
|
|
pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd,
|
|
NmsLocalAdd.Add.IPAdd);
|
|
|
|
if (pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd != NmsLocalAdd.Add.IPAdd)
|
|
{
|
|
|
|
//
|
|
// Send the reconfig message to the Pull thread
|
|
//
|
|
// Note: The PULL thread will deallocate memory pointed
|
|
// to be pWinsCnf when it gets done
|
|
//
|
|
ERplInsertQue(
|
|
WINS_E_WINSCNF,
|
|
QUE_E_CMD_ADDR_CHANGE,
|
|
NULL, //no dlg handle
|
|
NULL, //no msg
|
|
0, //msg len
|
|
NULL, //client ctx
|
|
0
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
WINSEVT_LOG_M(Error, WINS_EVT_SFT_ERR);
|
|
}
|
|
|
|
DBGLEAVE("CommInterfaceChangeNotification\n");
|
|
}
|
|
|
|
VOID
|
|
ECommRegisterAddrChange()
|
|
{
|
|
//--ft: bug 86768; 'overlap' shouldn't be allocated on the stack
|
|
//since it is passed down to WSAIoctl on an overlapped socket.
|
|
static WSAOVERLAPPED overlap;
|
|
DWORD Error;
|
|
DWORD byteRet;
|
|
|
|
RtlZeroMemory( &overlap, sizeof(WSAOVERLAPPED));
|
|
|
|
Error = WSAIoctl(
|
|
CommPnPNotificationSocket,
|
|
SIO_ADDRESS_LIST_CHANGE,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&byteRet,
|
|
&overlap,
|
|
CommInterfaceChangeNotification
|
|
);
|
|
|
|
if ( Error != ERROR_SUCCESS && Error == SOCKET_ERROR) {
|
|
|
|
Error = WSAGetLastError();
|
|
if (Error == WSA_IO_PENDING) {
|
|
Error = ERROR_SUCCESS;
|
|
} else {
|
|
DBGPRINT1( ERR,"SIO_INTERFACE_LIST_CHANGE ioctl failed, %ld.\n", Error );
|
|
}
|
|
}
|
|
if (Error != ERROR_SUCCESS ) {
|
|
|
|
WINSEVT_LOG_M(Error, WINS_EVT_SFT_ERR);
|
|
|
|
}
|
|
return ;
|
|
|
|
}
|
|
|
|
VOID
|
|
ECommInit(
|
|
VOID
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This function is called by the main thread of the process at
|
|
process invocation time. It initializes the communication subsystem.
|
|
This comprises of
|
|
|
|
1)create the TCP and UDP ports
|
|
2)create the TCP and UDP listener threads
|
|
|
|
|
|
None
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
Init() in nms.c
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Initialize lists, Tables and Memory
|
|
//
|
|
CommInit();
|
|
|
|
//
|
|
// Initialize the owner address table with own address
|
|
//
|
|
InitOwnAddTbl();
|
|
|
|
// Now register for address change notification
|
|
CommCreatePnPNotificationSocket();
|
|
ECommRegisterAddrChange();
|
|
|
|
//
|
|
// Create the TCP and UDP ports
|
|
//
|
|
CommCreatePorts( );
|
|
|
|
|
|
DBGIF(fWinsCnfRplEnabled)
|
|
//
|
|
// Signal Rpl PULL Thd so that it can go on
|
|
//
|
|
WinsMscSignalHdl(
|
|
RplSyncWTcpThdEvtHdl
|
|
);
|
|
|
|
//
|
|
// Init the event array used by ECommProcessDlg (in Push thread)
|
|
//
|
|
sThdEvtArr[0] = RplSyncWTcpThdEvtHdl;
|
|
sThdEvtArr[1] = NmsTermEvt;
|
|
|
|
/*
|
|
* Create the TCP listener thread to monitor the TCP port
|
|
*/
|
|
CommCreateTcpThd();
|
|
|
|
//
|
|
// if Wins is not coming up in the initially paused state, create
|
|
// the udp thread.
|
|
//
|
|
#if INIT_TIME_PAUSE_TEST > 0
|
|
// if (!fWinsCnfInitStatePaused)
|
|
{
|
|
/*
|
|
* Create the UDP listener thread to monitor the TCP port
|
|
*/
|
|
CommCreateUdpThd();
|
|
}
|
|
#else
|
|
CommCreateUdpThd();
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#if PRSCONN
|
|
__inline
|
|
ECommIsBlockValid
|
|
(
|
|
PCOMM_HDL_T pDlgHdl
|
|
)
|
|
{
|
|
return(CommIsBlockValid(pDlgHdl));
|
|
}
|
|
|
|
__inline
|
|
BOOL
|
|
ECommIsDlgActive
|
|
(
|
|
PCOMM_HDL_T pDlgHdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
pDlgHdl -- check if dlg is active
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
Replicator
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
#if 0
|
|
//
|
|
// Check if block is valid. It won't be if the dlg was terminated earlier
|
|
//
|
|
if (!CommIsBlockValid(pDlgHdl))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//
|
|
// Check whether the dlg is still active (i.e. the association is still
|
|
// valid.
|
|
// CommIsDlgActive is an inline function.
|
|
//
|
|
return(CommIsDlgActive(pDlgHdl));
|
|
|
|
}
|
|
#endif
|
|
|
|
STATUS
|
|
ECommStartDlg(
|
|
PCOMM_ADD_T pAdd, // Address
|
|
COMM_TYP_E CommTyp_e,
|
|
PCOMM_HDL_T pDlgHdl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
pAdd -- Address of the WINS server with which to start a dlg
|
|
CommTyp_e -- Type of dialogue (Pull, Push, Notifier, etc)
|
|
pDlgHdl -- Will contain handle to dlg on successful completion of
|
|
the function
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
Replicator
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes -- One of the STATUS codes (see wins.h)
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx;
|
|
STATUS RetStat = WINS_SUCCESS;
|
|
#ifdef WINSDBG
|
|
struct in_addr InAddr;
|
|
LPBYTE pstrAdd;
|
|
#endif
|
|
|
|
DBGENTER("ECommStartDlg\n");
|
|
|
|
/*
|
|
Allocate a dlg ctx block
|
|
*/
|
|
pDlgHdl->pEnt = CommAssocAllocDlg();
|
|
try {
|
|
pDlgCtx = pDlgHdl->pEnt;
|
|
pDlgCtx->Role_e = COMMASSOC_DLG_E_EXPLICIT;
|
|
pDlgCtx->Typ_e = CommTyp_e;
|
|
pDlgHdl->SeqNo = pDlgCtx->Top.SeqNo; //no need actually. (explicit dlg)
|
|
|
|
//
|
|
// Set up an association if we are not simulating an NBT node
|
|
//
|
|
if (CommTyp_e != COMM_E_NBT)
|
|
{
|
|
/*
|
|
* set up an association
|
|
*/
|
|
CommAssocSetUpAssoc(
|
|
pDlgHdl,
|
|
pAdd,
|
|
CommTyp_e,
|
|
&pAssocCtx
|
|
);
|
|
pDlgCtx->State_e = COMMASSOC_DLG_E_ACTIVE;
|
|
|
|
//
|
|
// No need to store sequence no. since there will never
|
|
// be a danger of the assoc. block being reused by some
|
|
// some other dialogue (this is an explicit dialogue)
|
|
//
|
|
pDlgCtx->AssocHdl.pEnt = pAssocCtx;
|
|
pDlgCtx->Typ_e = CommTyp_e;
|
|
}
|
|
else //simulate an NBT node
|
|
{
|
|
//
|
|
// Create a connection to the remote WINS
|
|
//
|
|
CommConnect(
|
|
pAdd,
|
|
#if SPX > 0
|
|
pAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP ? CommWinsTcpPortNo :
|
|
CommWinsSpxPortNo,
|
|
#else
|
|
CommWinsTcpPortNo,
|
|
#endif
|
|
&pDlgCtx->SockNo
|
|
);
|
|
}
|
|
|
|
} // end of try { }
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
//
|
|
// Cleanup and reraise the exception
|
|
//
|
|
CommAssocDeallocDlg(pDlgHdl->pEnt);
|
|
pDlgHdl->pEnt = NULL; //let us cover all bases. See SndPushNtf //in rplpull.c
|
|
WINS_RERAISE_EXC_M();
|
|
}
|
|
|
|
#ifdef WINSDBG
|
|
#if SPX == 0
|
|
InAddr.s_addr = htonl(pAdd->Add.IPAdd);
|
|
pstrAdd = inet_ntoa(InAddr);
|
|
#else
|
|
if (pAdd->Add.AddTyp_e == COMM_E_ADD_TCPUDPIP)
|
|
{
|
|
InAddr.s_addr = htonl(pAdd->Add.IPAdd);
|
|
pstrAdd = inet_ntoa(InAddr);
|
|
}
|
|
else
|
|
{
|
|
pstrAdd = pAdd->Add.nodenum;
|
|
}
|
|
#endif
|
|
|
|
DBGPRINT1(FLOW, "Leaving ECommStartDlg. Dlg started with Host at address -- (%s)\n", pstrAdd);
|
|
|
|
#endif
|
|
DBGLEAVE("ECommStartDlg\n");
|
|
return(RetStat);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ECommSndCmd(
|
|
IN PCOMM_HDL_T pDlgHdl,
|
|
IN MSG_T pMsg,
|
|
IN MSG_LEN_T MsgLen,
|
|
OUT PMSG_T ppRspMsg,
|
|
OUT PMSG_LEN_T pRspMsgLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is used by the Replicator to send commands to Replicators on remote WINSs. It is also used by the Name Space Manager of a Q
|
|
server to send name queriies to the Name Space Manager of an RQ server.
|
|
|
|
|
|
Arguments:
|
|
pDlgHdl -- handle to dialogue to use for sending command
|
|
pMsg -- Msg (Cmd) to send
|
|
MsgLen -- Length of Message
|
|
ppRspMsg -- Buffer containing response to command
|
|
pRspLen -- Length of response buffer
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
RplPull functions
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
DWORD MsgTyp;
|
|
DWORD Opc;
|
|
ULONG uTmp;
|
|
STATUS RetStat = WINS_SUCCESS;
|
|
|
|
|
|
/*
|
|
No need to lock the dialogue since:
|
|
|
|
currently, only the thread (excluding the COMSYS threads) that
|
|
creates a dialogue (explicit dialogue) sends messages on it.
|
|
|
|
|
|
In the future, when multiple threads share the same
|
|
dialogue, I will need to lock it or build an elaborate
|
|
asynch notification mechanism (for responses)
|
|
|
|
|
|
Also, there is no need to lock the associaation since only this
|
|
thread would ever look at it
|
|
*/
|
|
|
|
/*
|
|
* Send the command
|
|
*/
|
|
CommSend(
|
|
pDlgCtx->Typ_e,
|
|
&pDlgCtx->AssocHdl,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
|
|
pAssocCtx = pDlgCtx->AssocHdl.pEnt;
|
|
|
|
/*
|
|
Wait for a response
|
|
*/
|
|
RetStat = CommReadStream(
|
|
pAssocCtx->SockNo,
|
|
TRUE, //do timed recv
|
|
ppRspMsg,
|
|
pRspMsgLen
|
|
);
|
|
|
|
/*
|
|
if bytes read are 0, there was a disconnect. If RetStat is not
|
|
success, maybe the recv. timed out or the most severe of
|
|
all conditions, maybe the SOCKET_ERROR got returned by
|
|
the first RecvData() call in CommReadStream. As far as the
|
|
client is concerned, all of these conditions indicate
|
|
COMM failure to it. Let us raise that exception.
|
|
*/
|
|
if (( *pRspMsgLen == 0) || (RetStat != WINS_SUCCESS))
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
COMM_GET_HEADER_M(*ppRspMsg, Opc, uTmp, MsgTyp);
|
|
|
|
/*
|
|
Let us check that this is not the stop assoc message
|
|
*/
|
|
if (MsgTyp == COMM_STOP_REQ_ASSOC_MSG)
|
|
{
|
|
//
|
|
// We do not disconnect the socket. It will be disconnected as
|
|
// a result of an end dialogue on this explicit association
|
|
//
|
|
// CommDisc(pAssocCtx->SockNo);
|
|
|
|
//
|
|
// Free the buffer
|
|
//
|
|
ECommFreeBuff(*ppRspMsg);
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
/*
|
|
* Strip off the header before returning to the client
|
|
* (Replicator)
|
|
*/
|
|
*ppRspMsg = *ppRspMsg + COMM_HEADER_SIZE;
|
|
*pRspMsgLen = *pRspMsgLen - COMM_HEADER_SIZE;
|
|
|
|
return;
|
|
} // ECommSndCmd
|
|
|
|
|
|
|
|
|
|
|
|
STATUS
|
|
ECommSndRsp(
|
|
PCOMM_HDL_T pDlgHdl,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by the Comm. clients to send messages to
|
|
destinations identified by the dialogue. No responses are expected to
|
|
these messages.
|
|
|
|
The function is used for sending responses.
|
|
|
|
Arguments:
|
|
|
|
pDlgHdl - handle to dlg to use for sending response
|
|
pMsg - message (response) to send
|
|
MsgLen - length of message
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
NmsNmh functions, RplPush functions
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes --
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOL fLocked = FALSE;
|
|
STATUS RetStat = WINS_SUCCESS;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
|
|
DBGENTER("ECommSndRsp\n");
|
|
FUTURES("Since we do not want the overhead of an if test for responding")
|
|
FUTURES("to nbt requests, split up this function into one callable by")
|
|
FUTURES("replicator and the other one by NBT threads. Do note that ")
|
|
FUTURES("this will take away some cleanliness of interfacing with COMM")
|
|
|
|
try {
|
|
|
|
/*
|
|
Check if the dialogue is for UDP communication. If it is, there
|
|
is no need for any synchronization.
|
|
|
|
There is no need to lock the dialogue prior to checking it because
|
|
|
|
if it is a UDP dialogue, it has to be the one that was allocated
|
|
for this request (i.e. there is no possibility that we are now
|
|
looking at another UDP dialogue).
|
|
|
|
*/
|
|
if (pDlgCtx->Typ_e != COMM_E_UDP)
|
|
{
|
|
/*
|
|
* Lock the dialogue block so that it is not deleted from
|
|
* under us. Actually, as things stand currently, an explicit
|
|
* dialogue is never used by more than one thread. So, we don't
|
|
* have to lock a dialogue if it is an explicit dialogue. Let
|
|
* us do it anyway since in the forseeable future, we could have
|
|
* multiple threads using the same dialogue (Replicator threads -
|
|
* Pull and Notifier). This is small insurance to save us
|
|
* from later headaches.
|
|
*/
|
|
|
|
fLocked = CommLockBlock(pDlgHdl);
|
|
if (fLocked)
|
|
{
|
|
CommSend(
|
|
pDlgCtx->Typ_e,
|
|
&pDlgCtx->AssocHdl,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
}
|
|
else //dialogue could not be locked
|
|
{
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_LOCK_ERR);
|
|
DBGPRINT0(ERR, "ECommSndRsp: Could not lock the dialogue\n");
|
|
/*
|
|
*If Dialogue block could not be locked, it means
|
|
*that it was freed by the TCP listener thread (Check
|
|
*DelAssoc() in comm.c). This would happen only
|
|
*if the connection terminated or if a stop assoc
|
|
*message was received on it.
|
|
|
|
*Return a COMM_FAIL error. This will return in
|
|
*a search for a termination handler. It is *ok*
|
|
* to take this overhead since this is a
|
|
* rare error case
|
|
*/
|
|
|
|
return(WINS_COMM_FAIL);
|
|
}
|
|
|
|
if (CommUnlockBlock(pDlgHdl) == WINS_FAILURE)
|
|
{
|
|
RetStat = WINS_FAILURE;
|
|
}
|
|
else //successfully unlocked the dialogue
|
|
{
|
|
|
|
fLocked = FALSE;
|
|
}
|
|
}
|
|
else // it is dialogue for UDP communication with an NBT node
|
|
{
|
|
CommSendUdp(
|
|
0,
|
|
&(pDlgCtx->FromAdd),
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
/*
|
|
We have sent the response. We should now get rid of
|
|
the dialogue from the dialogue table. This will
|
|
free the heap memory
|
|
*/
|
|
CommAssocDeleteUdpDlgInTbl( pDlgCtx );
|
|
}
|
|
}
|
|
|
|
finally {
|
|
|
|
if (fLocked)
|
|
{
|
|
CommUnlockBlock(pDlgHdl);
|
|
}
|
|
}
|
|
|
|
DBGLEAVE("ECommSndRsp\n");
|
|
return(RetStat);
|
|
|
|
}
|
|
|
|
STATUS
|
|
ECommSendMsg(
|
|
PCOMM_HDL_T pDlgHdl,
|
|
PCOMM_ADD_T pAdd,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used by the name challenge manager to send queries
|
|
and release request to nbt nodes.
|
|
|
|
It is also used by the replicator to send a Push notification to
|
|
a WINS (pull pnr)
|
|
|
|
Arguments:
|
|
pDlgHdl - handle to dlg to use for sending message
|
|
pAdd - Address of node to send message to
|
|
pMsg - Message to send
|
|
MsgLen - Length of message to send
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
NmsChl functions
|
|
|
|
Comments:
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes --
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
struct sockaddr_in TgtAdd;
|
|
|
|
//
|
|
// if the dialogue is mapped to the UDP port, send a UDP packet
|
|
//
|
|
if (pDlgCtx->Typ_e == COMM_E_UDP)
|
|
{
|
|
//
|
|
// Don't change from host to net order. CommSendUdp does
|
|
// that
|
|
//
|
|
TgtAdd.sin_addr.s_addr = pAdd->Add.IPAdd;
|
|
if(TgtAdd.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
TgtAdd.sin_family = PF_INET;
|
|
TgtAdd.sin_port = htons(WINS_NBT_PORT);
|
|
|
|
//
|
|
// Send the message via netbt
|
|
//
|
|
CommSendUdp( 0, &TgtAdd, pMsg, MsgLen );
|
|
}
|
|
else // it is a dialogue mapped to a TCP connection
|
|
{
|
|
//
|
|
// Send the message
|
|
//
|
|
CommSend(
|
|
pDlgCtx->Typ_e,
|
|
&pDlgCtx->AssocHdl,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
}
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
STATUS
|
|
ECommEndDlg(
|
|
PCOMM_HDL_T pDlgHdl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This function is used to end a dialogue.
|
|
|
|
|
|
The processing depends upon the type of dialogue
|
|
|
|
1)if the dlg is an implicit UDP dialogue. it is deleted from
|
|
the dlg table and the memory is freed.
|
|
|
|
2)if the dlg is an implicit dlg, a stop assoc.
|
|
message is sent on the association
|
|
|
|
3)if the dlg is an explicit dlg, a stop assoc. message is
|
|
message is sent on the association and the association is
|
|
terminated
|
|
|
|
|
|
Arguments:
|
|
pDlgHdl - Handle to dlg to end
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
RplPull functions, HandleUpdNtf in rplpush.c (by the Push thread)
|
|
|
|
Comments:
|
|
Currently, there is no need to lock an explicit dialogue since only
|
|
one thread accesses it any time (currently). In the future, if we
|
|
have multiple threads accessing the same dialogue, we will do locking
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes --
|
|
|
|
--*/
|
|
|
|
{
|
|
BYTE Msg[COMMASSOC_ASSOC_MSG_SIZE];
|
|
DWORD MsgLen = COMMASSOC_ASSOC_MSG_SIZE;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
BOOL fLocked;
|
|
|
|
DBGENTER("ECommEndDlg\n");
|
|
//
|
|
// If there is no dialogue to be ended, return WINS_INVALID_HDL
|
|
// Note: There can be cases in failure recovery where ECommEndDlg
|
|
// may be called to end a dialogue that was never got started or
|
|
// got ended prematurely. Though an error status is returned, the
|
|
// caller, when doing failure recovery, may ignore the return status
|
|
// of this function. In case of fatal error conditions, an exception
|
|
// will be raised which the caller can not ignore.
|
|
//
|
|
if (pDlgCtx == NULL)
|
|
{
|
|
DBGLEAVE("ECommEndDlg\n");
|
|
return(WINS_INVALID_HDL);
|
|
}
|
|
|
|
//
|
|
// In case it is an implicit UDP dialogue, there is no danger
|
|
// of it being freed from under us, so there is no need to lock.
|
|
// In case it is an implicit TCP dialogue, it could get freed
|
|
// and even reallocated from under us, but reallocation will only
|
|
// be for TCP, so there is no danger since we do lock the dlg
|
|
// block if it is a TCP dlg block (if there has been a reallocation,
|
|
// the lock attempt will fail.)
|
|
//
|
|
if (pDlgCtx->Role_e == COMMASSOC_DLG_E_IMPLICIT)
|
|
{
|
|
if (pDlgCtx->Typ_e == COMM_E_UDP)
|
|
{
|
|
//
|
|
// Delete the dialogue from the table and free the
|
|
// heap memory
|
|
//
|
|
CommAssocDeleteUdpDlgInTbl( pDlgCtx );
|
|
}
|
|
else // it is a TCP dialogue.
|
|
{
|
|
|
|
fLocked = CommLockBlock(pDlgHdl);
|
|
|
|
//
|
|
// If we could lock it, the dlg is ok. If we could not
|
|
// lock it, it means that the dlg was freed due to the
|
|
// the assoc. going down. We have nothing more to do.
|
|
//
|
|
if (fLocked)
|
|
{
|
|
pAssocCtx = pDlgCtx->AssocHdl.pEnt;
|
|
|
|
//
|
|
// The stop assoc. message will result in the
|
|
// the other WINS terminating the connection which
|
|
// result in all cleanup at our end
|
|
//
|
|
CommAssocFrmStopAssocReq(
|
|
pAssocCtx,
|
|
Msg,
|
|
MsgLen,
|
|
COMMASSOC_E_MSG_ERR
|
|
);
|
|
try {
|
|
|
|
CommSendAssoc(
|
|
pAssocCtx->SockNo,
|
|
Msg,
|
|
MsgLen
|
|
);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
//
|
|
// No need to do any cleanup. This is an
|
|
// implicit dlg. The tcp listener thread will
|
|
// do the cleanup. Currently, it never calls
|
|
// ECommEndDlg for an implicit dlg so the client
|
|
// has got to be rpl
|
|
//
|
|
DBGPRINTEXC("CommEndDlg");
|
|
}
|
|
|
|
CommUnlockBlock(pDlgHdl);
|
|
}
|
|
}
|
|
}
|
|
else // it is an explicit dialogue
|
|
{
|
|
if (pDlgCtx->Typ_e != COMM_E_NBT)
|
|
{
|
|
CommEndAssoc(&pDlgCtx->AssocHdl);
|
|
}
|
|
|
|
/*
|
|
* Dealloc the dialogue in order to put it in the free list
|
|
*/
|
|
CommAssocDeallocDlg( pDlgCtx );
|
|
#if PRSCONN
|
|
FUTURES("Init the dlg hdl in the caller - good software engineering practice")
|
|
//
|
|
// The dlg is ended. Let us init the dlg hdl to null so that
|
|
// it is not used again. Strictly speaking, we should do let
|
|
// the caller do this. For now, we will do it here
|
|
//
|
|
ECOMM_INIT_DLG_HDL_M(pDlgHdl);
|
|
#endif
|
|
}
|
|
|
|
DBGLEAVE("ECommEndDlg\n");
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
ECommSendtoAllQ(
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to send a message to all Q servers.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
|
|
Comments:
|
|
May use it in the future. Needs work.
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
/*
|
|
if there is no dialogue pertaining to a Q server, return failure
|
|
*/
|
|
|
|
if (IsListEmpty(&QservDlgList))
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
|
|
/*
|
|
find all the dialogues pertaining to Q servers
|
|
*/
|
|
|
|
while ((pQservDlg = GetNext(&QservDlgList)) != &QservDlgList)
|
|
{
|
|
CommSendAssoc(pQservDlg->pAssocCtx->SockNo, pMsg, MsgLen);
|
|
}
|
|
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
#endif
|
|
|
|
STATUS
|
|
ECommAlloc(
|
|
OUT LPVOID *ppBuff,
|
|
IN DWORD BuffSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by by the replicator to allocate a buffer for
|
|
sending to another WINS (over a TCP connection)
|
|
|
|
|
|
Arguments:
|
|
ppBuff - Buffer allocated by function
|
|
BuffSize - Size of buffer to be allocated
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
|
|
Challenge manager should not call this function. When it is coded,
|
|
it will call AllocUdpBuff which will be made an external for this
|
|
purpose (CommAllocUdpBuff)
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD Size = COMM_HEADER_SIZE +
|
|
sizeof(COMM_BUFF_HEADER_T) + sizeof(LONG);
|
|
PCOMM_BUFF_HEADER_T pCommHdr;
|
|
|
|
WinsMscAlloc( Size + BuffSize, ppBuff);
|
|
#if 0
|
|
*ppBuff = CommAlloc(
|
|
NULL, //no table
|
|
Size + BuffSize
|
|
);
|
|
#endif
|
|
pCommHdr = (PCOMM_BUFF_HEADER_T)((LPBYTE)(*ppBuff) + sizeof(LONG));
|
|
pCommHdr->Typ_e = COMM_E_TCP; //until we know better
|
|
*ppBuff = (LPBYTE)(*ppBuff) + Size;
|
|
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
#if 0
|
|
|
|
VOID
|
|
ECommDealloc(
|
|
LPVOID pBuff
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a wrapper around CommDealloc. It conforms to the
|
|
prototype required by RtlInitializeGenericTbl func.
|
|
|
|
Arguments:
|
|
|
|
pBuf -- Buffer to deallocate
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
Not being used currently
|
|
--*/
|
|
{
|
|
LPVOID pTmp = (LPBYTE)pBuff - COMM_HEADER_SIZE;
|
|
|
|
WinsMscDealloc(pTmp);
|
|
#if 0
|
|
CommDealloc(NULL, pTmp);
|
|
#endif
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
DWORD
|
|
ECommCompAdd(
|
|
PCOMM_ADD_T pFirstAdd,
|
|
PCOMM_ADD_T pSecAdd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
the function compares two host addresses
|
|
|
|
Arguments:
|
|
|
|
pFirstAdd - Address of a node
|
|
pSecondAdd - Address of a node
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
COMM_SAME_ADD
|
|
COMM_DIFF_ADD
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
#if 0
|
|
if ((pFirstAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP) &&
|
|
(pSecAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP))
|
|
#endif
|
|
{
|
|
if (pFirstAdd->Add.IPAdd == pSecAdd->Add.IPAdd)
|
|
{
|
|
return(COMM_SAME_ADD);
|
|
}
|
|
}
|
|
return(COMM_DIFF_ADD);
|
|
}
|
|
|
|
int
|
|
__cdecl
|
|
ECommCompareAdd(
|
|
const void *pKey1,
|
|
const void *pKey2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
the function compares two host addresses
|
|
|
|
Arguments:
|
|
|
|
pFirstAdd - Address of a node
|
|
pSecondAdd - Address of a node
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
const COMM_ADD_T *pFirstAdd = pKey1;
|
|
const COMM_ADD_T *pSecAdd = pKey2;
|
|
|
|
return (pFirstAdd->Add.IPAdd > pSecAdd->Add.IPAdd) ?
|
|
1 :
|
|
(pFirstAdd->Add.IPAdd < pSecAdd->Add.IPAdd) ?
|
|
-1:
|
|
0;
|
|
}
|
|
|
|
VOID
|
|
ECommFreeBuff(
|
|
IN MSG_T pMsg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to free a buffer allocated earlier by
|
|
COMSYS. The function checks the buffer header to determine which
|
|
deallocation function to call
|
|
|
|
The usefulness of this function stems from the fact that a buffer
|
|
can be made independent of the dialogue (or association) it came from
|
|
in the sense that we don't need to pass information about such a
|
|
dlg or assoc when freeing the buffer. This saves us from locking
|
|
and unlocking.
|
|
|
|
Arguments:
|
|
|
|
pMsg -- Buffer to free
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
SndNamRegRsp, SndNamRelRsp, SndNamQueryRsp in nmsnmh.c
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
#if USENETBT > 0
|
|
PCOMM_BUFF_HEADER_T pHdr = (PCOMM_BUFF_HEADER_T)
|
|
(pMsg - COMM_NETBT_REM_ADD_SIZE -
|
|
sizeof(COMM_BUFF_HEADER_T));
|
|
#else
|
|
PCOMM_BUFF_HEADER_T pHdr = (PCOMM_BUFF_HEADER_T)
|
|
(pMsg - sizeof(COMM_BUFF_HEADER_T));
|
|
#endif
|
|
|
|
if (pHdr->Typ_e == COMM_E_UDP)
|
|
{
|
|
|
|
WinsMscHeapFree(
|
|
CommUdpBuffHeapHdl,
|
|
pHdr
|
|
);
|
|
}
|
|
else
|
|
{
|
|
WinsMscHeapFree(CommAssocTcpMsgHeapHdl, (LPBYTE)pHdr - sizeof(LONG));
|
|
// WinsMscDealloc((LPBYTE)pHdr - sizeof(LONG));
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
InitOwnAddTbl(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function uses the local address of the WINS (i.e. the host
|
|
address) to overwrite the NmsDbOwnAddTbl array entry
|
|
pertaining to the local WINS if different
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
CommInit (in the main thread)
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
There is no need to synchronize over the NmsDbOwnAddTbl since
|
|
the PULL thread will not touch it until it initiates the pull protocol
|
|
--*/
|
|
|
|
{
|
|
COMM_IP_ADD_T IPAddInDbTbl;
|
|
|
|
//
|
|
// if the address of the owner with owner id = NMSDB_LOCAL_OWNER_ID
|
|
// is different from mine (i.e. local WINS)
|
|
// change it to mine. I always own all entries tagged with
|
|
// owner id of 0. The fact that the address is different
|
|
// means that the database was earlier used by a WINS at
|
|
// a different address.
|
|
//
|
|
IPAddInDbTbl = pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd;
|
|
if (
|
|
IPAddInDbTbl != NmsLocalAdd.Add.IPAdd
|
|
)
|
|
{
|
|
|
|
|
|
//
|
|
// IPAddInDbTbl will be zero if there is no entry in the
|
|
// local db having NMSDB_LOCAL_OWNER_ID as the owner field
|
|
// value
|
|
//
|
|
NmsDbWriteOwnAddTbl (
|
|
IPAddInDbTbl == 0 ?
|
|
NMSDB_E_INSERT_REC : NMSDB_E_MODIFY_REC,
|
|
NMSDB_LOCAL_OWNER_ID,
|
|
&NmsLocalAdd,
|
|
NMSDB_E_WINS_ACTIVE,
|
|
&NmsDbStartVersNo,
|
|
&NmsDbUid
|
|
);
|
|
|
|
pNmsDbOwnAddTbl->WinsAdd = NmsLocalAdd;
|
|
pNmsDbOwnAddTbl->WinsState_e = NMSDB_E_WINS_ACTIVE;
|
|
pNmsDbOwnAddTbl->MemberPrec = WINSCNF_HIGH_PREC;
|
|
pNmsDbOwnAddTbl->StartVersNo = NmsDbStartVersNo;
|
|
pNmsDbOwnAddTbl->Uid = NmsDbUid;
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ECommProcessDlg(
|
|
PCOMM_HDL_T pDlgHdl,
|
|
COMM_NTF_CMD_E Cmd_e
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to either start or stop monitoring a
|
|
dialogue. It sends a message to the TCP listener thread (a UDP
|
|
datagram) on the notification socket.
|
|
|
|
Arguments:
|
|
pDlgHdl - Dialogue handle
|
|
Cmd_e - Cmd (COMM_E_NTF_START_MON or COMM_E_NTF_STOP_MON)
|
|
|
|
Externals Used:
|
|
RplSyncWTcpThdEvtHdl
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
SndUpdNtf in rplpull.c, HdlUpdNtf in rplpush.c
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
The client should not expect to use the dailogue after calling
|
|
this functions
|
|
|
|
Only the Push thread calls this function
|
|
|
|
--*/
|
|
|
|
{
|
|
COMM_NTF_MSG_T NtfMsg;
|
|
BOOL fRetStat = TRUE;
|
|
DWORD ArrInd;
|
|
|
|
|
|
DBGENTER("ECommProcessDlg\n");
|
|
|
|
//
|
|
//Format the message to send in the UDP datagram
|
|
//
|
|
if (CommLockBlock(pDlgHdl))
|
|
{
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
|
|
|
|
NtfMsg.SockNo = pAssocCtx->SockNo;
|
|
NtfMsg.Cmd_e = Cmd_e;
|
|
NtfMsg.AssocHdl = pDlgCtx->AssocHdl;
|
|
NtfMsg.DlgHdl = *pDlgHdl;
|
|
|
|
CHECK("If TCP protocol is installed. If not, use the Spx notification socket")
|
|
|
|
CommUnlockBlock(pDlgHdl);
|
|
|
|
CommSendUdp(
|
|
CommNtfSockHandle,
|
|
//CommUdpPortHandle, //sending port
|
|
&CommNtfSockAdd, //Address to send to
|
|
(LPBYTE)&NtfMsg, //socket no to send
|
|
COMM_NTF_MSG_SZ
|
|
);
|
|
|
|
DBGPRINT2(DET,
|
|
"ECommProcessDlg: Sent %s monitoring message to TCP listener thread for socket no (%d)\n",
|
|
Cmd_e == COMM_E_NTF_START_MON ? "start" : "stop",
|
|
NtfMsg.SockNo
|
|
);
|
|
|
|
//
|
|
// if the command is to "stop monitoring the dlg" we have to wait
|
|
// until the TCP listener thread has receive this message and
|
|
// taken the socket out of its array of sockets
|
|
//
|
|
if (Cmd_e == COMM_E_NTF_STOP_MON)
|
|
{
|
|
//
|
|
//Wait to be signaled by the TCP listener thread indicating that
|
|
// it has removed the socket from the list of sockets that it
|
|
// is monitoring. We also want to check the term. event since
|
|
// the tcp thread may have terminated as a result of
|
|
// a termination of WINS.
|
|
//
|
|
//WinsMscWaitInfinite(RplSyncWTcpThdEvtHdl);
|
|
WinsMscWaitUntilSignaled(
|
|
sThdEvtArr,
|
|
sizeof(sThdEvtArr)/sizeof(HANDLE),
|
|
&ArrInd,
|
|
FALSE
|
|
);
|
|
|
|
if (ArrInd == 0)
|
|
{
|
|
if (fCommDlgError)
|
|
{
|
|
DBGPRINT0(ERR, "ECommProcessDlg: The tcp listener thread indicated that the IMPLICIT assoc has been deallocated. TIMING WINDOW\n");
|
|
fRetStat = FALSE;
|
|
fCommDlgError = FALSE;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//Signaled for termination
|
|
//
|
|
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(ERR, "ECommProcessDlg: Could not lock the (%s) dlg block. Maybe the assocication and dialogue got deallocated\n", Cmd_e == COMM_E_NTF_STOP_MON ? "IMPLICIT" : "EXPLICIT");
|
|
fRetStat = FALSE;
|
|
}
|
|
//
|
|
// All done. Return
|
|
//
|
|
DBGLEAVE("ECommProcessDlg\n");
|
|
return(fRetStat);
|
|
}
|
|
|
|
//--ft: 11/30/99
|
|
STATUS
|
|
CommRaiseMyDnsAdd(
|
|
IN OUT LPSOCKET_ADDRESS_LIST pAddrList
|
|
)
|
|
//++
|
|
//Routine Description:
|
|
//
|
|
// This function is called to find out the address returned by DNS when
|
|
// the server address is queried through gethostbyname().
|
|
//
|
|
//Arguments:
|
|
// pAddrList - the list of local interfaces as returned by WSAIoctl(SIO_ADDRESS_LIST_QUERY)
|
|
//--
|
|
{
|
|
DWORD Error = ERROR_SUCCESS;
|
|
struct hostent *pHostEnt;
|
|
BYTE HostName[NMSDB_MAX_NAM_LEN];
|
|
CHAR **pHostIter;
|
|
|
|
// Get host's name
|
|
if (gethostname(HostName, NMSDB_MAX_NAM_LEN) == SOCKET_ERROR)
|
|
{
|
|
return WSAGetLastError();
|
|
}
|
|
|
|
// Get host's HOSTENT structure
|
|
pHostEnt = gethostbyname(HostName);
|
|
|
|
if (pHostEnt == NULL)
|
|
{
|
|
return WSAGetLastError();
|
|
}
|
|
|
|
// For each address returned by DNS
|
|
for (pHostIter = pHostEnt->h_addr_list; (*pHostIter) != NULL; pHostIter++)
|
|
{
|
|
INT i;
|
|
|
|
// For each address in the interfaces list
|
|
for (i = 0; i < pAddrList->iAddressCount; i++)
|
|
{
|
|
LPSOCKADDR_IN pSockIf = (LPSOCKADDR_IN)(pAddrList->Address[i].lpSockaddr);
|
|
|
|
// it is assumed the address is IP (DWORD size)
|
|
if (WINSMSC_COMPARE_MEMORY_M(
|
|
(*pHostIter),
|
|
&(pSockIf->sin_addr),
|
|
pHostEnt->h_length) == (UINT)pHostEnt->h_length)
|
|
{
|
|
// bring the DNS address in front of the interfaces list if needed
|
|
// this is where the address to be used will be picked up from
|
|
if (i != 0)
|
|
{
|
|
LPSOCKADDR_IN pSockIfAtZero = (LPSOCKADDR_IN)(pAddrList->Address[0].lpSockaddr);
|
|
WINSMSC_COPY_MEMORY_M(
|
|
pSockIfAtZero,
|
|
pSockIf,
|
|
sizeof(SOCKADDR_IN)
|
|
);
|
|
}
|
|
// return success
|
|
return Error;
|
|
} // end_if success in matching dns address with if address
|
|
} // end_for each interface address
|
|
} // end_for each dns address
|
|
|
|
// at this point is kind'a weird: either no DNS address could be found in the interfaces list
|
|
// or the interfaces list is just empty (no interfaces?)
|
|
// in either cases, this will be handled by the caller - the interfaces list is untouched
|
|
return Error;
|
|
}
|
|
|
|
STATUS
|
|
ECommGetMyAdd(
|
|
IN OUT PCOMM_ADD_T pAdd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to find out the name and address of the
|
|
local machine and store it for later use.
|
|
|
|
Arguments:
|
|
pAdd - pointer to buffer to contain the address
|
|
|
|
Externals Used:
|
|
NmsLocalAdd
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
Init() in nms.c
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
THIS MUST BE THE FIRST COMM FUNCTION TO BE CALLED IN WINS. This
|
|
is so that WSAStartup is called prior to calling any winsock functions
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD Error;
|
|
int RetVal;
|
|
DWORD RetStat = WINS_SUCCESS;
|
|
NTSTATUS RetStatus;
|
|
static BOOL bWSAStarted = FALSE;
|
|
WSADATA wskData;
|
|
DBGENTER("ECommGetMyAdd\n");
|
|
/*
|
|
* Let us call the WSAStartup function. This function needs
|
|
* to be called before any other wins socket function can be
|
|
* called.
|
|
*/
|
|
|
|
// added the bWSAStarted variable to avoid making several subsequent
|
|
// calls to WSAStartup. Also it looks like there is no matching
|
|
// WSACleanup call at this time.
|
|
if (!bWSAStarted)
|
|
{
|
|
if (WSAStartup(0x101, &wskData) || (wskData.wVersion != 0x101))
|
|
{
|
|
WinsEvtLogDetEvt(
|
|
FALSE,
|
|
WINS_PNP_FAILURE,
|
|
NULL,
|
|
__LINE__,
|
|
"d",
|
|
WINS_EXC_FATAL_ERR);
|
|
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
bWSAStarted = TRUE;
|
|
}
|
|
|
|
//
|
|
// If this is a cluster machine, always use cluster Ip resource address
|
|
//
|
|
if (WinsClusterIpAddress)
|
|
{
|
|
pAdd->Add.IPAdd = WinsClusterIpAddress;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwAddrListSz = 0; // size of the ioctl out buffer
|
|
LPSOCKET_ADDRESS_LIST pAddrList = NULL; // pointer to the ioctl out buffer
|
|
|
|
Error = CommCreatePnPNotificationSocket();
|
|
|
|
if (Error == ERROR_SUCCESS)
|
|
{
|
|
// make one Ioctl call to get the required size of the output buffer
|
|
// this should fail with SOCKET_ERROR and with LastError = WSAEFAULT
|
|
Error = WSAIoctl(
|
|
CommPnPNotificationSocket,
|
|
SIO_ADDRESS_LIST_QUERY,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&dwAddrListSz,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
// if CommCreatePnPNotificationSocket failed, Error is supposed to be a WSAError
|
|
// and not SOCKET_ERROR. This avoids calling WSAIoctl a second time and the error
|
|
// will be captured in the next if()
|
|
// we should get an error with the LastError = WSAEFAULT
|
|
if (Error == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT)
|
|
{
|
|
WinsMscAlloc(dwAddrListSz, &pAddrList);
|
|
// make a second IoctlCall in order to get the list of addresses in
|
|
// the newly allocated buffer. This is expected to succeed
|
|
Error = WSAIoctl(
|
|
CommPnPNotificationSocket,
|
|
SIO_ADDRESS_LIST_QUERY,
|
|
NULL,
|
|
0,
|
|
pAddrList,
|
|
dwAddrListSz,
|
|
&dwAddrListSz,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
// on success, go raise the first address known by DNS
|
|
// this hack is needed in order to get the first adaptor from the binding list.
|
|
// It seems like gethostbyname returns the adaptors in binding order while WSAIoctl does not.
|
|
if (Error == 0)
|
|
{
|
|
// this is another hack: it looks like DNS is not refreshing the addresses instantly. For instance,
|
|
// plugging out the cable for the first ip from the DNS list triggers CommInterfaceChangeNotification
|
|
// but while in this function gethostbyname() still shows the address that went away as the first
|
|
// one in the list. Add 1/2 sec delay here to let DNS update its addresses and after that attempt
|
|
// to raise in the list returned by SIO_ADDRESS_LIST_QUERY the first address known by DNS.
|
|
Sleep(500);
|
|
Error = CommRaiseMyDnsAdd(pAddrList);
|
|
}
|
|
|
|
if (Error != 0)
|
|
{
|
|
Error = WSAGetLastError();
|
|
|
|
WinsEvtLogDetEvt(
|
|
FALSE,
|
|
WINS_PNP_FAILURE,
|
|
NULL,
|
|
__LINE__,
|
|
"d",
|
|
Error);
|
|
|
|
DBGPRINT1(ERR,
|
|
"ECommGetMyAdd:WSAIoctl(SIO_ADDRESS_LIST_QUERY) failed with error %d\n", Error);
|
|
|
|
if (pAddrList != NULL)
|
|
{
|
|
WinsMscDealloc(pAddrList);
|
|
pAddrList = NULL;
|
|
}
|
|
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
if (pAddrList->iAddressCount > 0)
|
|
{
|
|
// why fooling around - pAdd->Add.IPAdd is a DWORD anyhow.
|
|
pAdd->Add.IPAdd =
|
|
((LPSOCKADDR_IN)(pAddrList->Address[0].lpSockaddr))->sin_addr.s_addr;
|
|
}
|
|
else
|
|
{
|
|
// just in case no addresses were passed up by the Ioctl, set the address
|
|
// to 0. It will be seen as such a couple lines down.
|
|
pAdd->Add.IPAdd = 0;
|
|
}
|
|
|
|
if (pAddrList != NULL)
|
|
{
|
|
WinsMscDealloc(pAddrList);
|
|
pAddrList = NULL;
|
|
}
|
|
|
|
//
|
|
// Initialize the structure
|
|
//
|
|
pAdd->Add.IPAdd = ntohl(pAdd->Add.IPAdd);
|
|
}
|
|
|
|
//
|
|
// This prints the address in reverse order, that's ok
|
|
//
|
|
DBGPRINT1(DET, "ECommGetMyAdd: Binding to Nbt interface %s\n",
|
|
inet_ntoa(*(struct in_addr *)&pAdd->Add.IPAdd));
|
|
|
|
|
|
//
|
|
// If we have a 0 address or a loopback address, it means that the
|
|
// address went away. Wait for one to come back.
|
|
//
|
|
if ((WinsCnf.State_e != WINSCNF_E_TERMINATING) &&
|
|
((pAdd->Add.IPAdd & 0xff000000) != (INADDR_LOOPBACK & 0xff000000)) &&
|
|
(pAdd->Add.IPAdd != 0))
|
|
{
|
|
try
|
|
{
|
|
if (WinsCnfNbtHandle)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
tWINS_SET_INFO setInfo;
|
|
|
|
// if there is already a Nbt handle, just rebind it
|
|
setInfo.IpAddress = pAdd->Add.IPAdd;
|
|
|
|
// this ioctl is just notifying NetBt on the address change.
|
|
// it should succeed with STATUS_SUCCESS - no reason for 'pending'
|
|
// hence no reason for passing down an Apc or an event handle.
|
|
status = NtDeviceIoControlFile(
|
|
WinsCnfNbtHandle, // Handle
|
|
NULL, // Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&iosb, // IoStatusBlock
|
|
IOCTL_NETBT_WINS_SET_INFO, // IoControlCode
|
|
&setInfo, // InputBuffer
|
|
sizeof(tWINS_SET_INFO), // Buffer Length
|
|
NULL, // Output Buffer
|
|
0 // Output BufferSize
|
|
);
|
|
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
// open netbt handle with interface having this address
|
|
CommOpenNbt(pAdd->Add.IPAdd);
|
|
}
|
|
|
|
// We need to get all netbt interfaces' Ip addresses. They are sent
|
|
// via multicast packet to other wins servers to support find self
|
|
// partner feature.
|
|
CommGetNetworkAdd();
|
|
|
|
pAdd->AddTyp_e = COMM_ADD_E_TCPUDPIP;
|
|
pAdd->AddLen = sizeof(COMM_IP_ADD_T);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WinsEvtLogDetEvt(
|
|
FALSE,
|
|
WINS_PNP_FAILURE,
|
|
NULL,
|
|
__LINE__,
|
|
"d",
|
|
GetExceptionCode());
|
|
|
|
WINS_RERAISE_EXC_M();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RetStat = WINS_FAILURE;
|
|
}
|
|
|
|
DBGLEAVE("ECommGetMyAdd\n");
|
|
return(RetStat);
|
|
}
|