Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3786 lines
105 KiB

/*
Possible improvements
If there were a way to end all sessions with one Jet call, there would be
no need to have each nbt thread call WinsMscWaitUntilSignaled. It could simply
call WaitForSingleObject.
*/
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
nms.c
Abstract:
This module contains functions used by the name space manager (NMS)
This is the top-most module of the name space manager component of
WINS. It contains functions used for initializing WINS and for
providing an interface nto NMS to other components to WINS.
Functions:
main
WinsMain
Init
CreateNbtThdPool
NbtThdInitFn
CreateMem
ENmsHandleMsg
NmsAllocWrkItm
NmsDeallocWrkItm
NmsServiceControlHandler
SignalWinsThds
UpdateStatus
WrapUp
Portability:
This module is portable across various platforms
Author:
Pradeep Bahl (PradeepB) Dec-1992
Revision History:
Modification date Person Description of modification
----------------- ------- ----------------------------
--*/
#include "wins.h"
#include <lmerr.h>
#include <lmcons.h>
#include <secobj.h> //required for ACE_DATA
#include "winsif.h" //required because winsif_v1_0_s_ifspec is being
//referenced
#include "winsi2.h"
#ifdef WINSDBG
#include <time.h>
#endif
#include "winscnf.h"
#include "nmsdb.h"
#include "winsque.h"
#include "winsthd.h"
#include "comm.h"
#include "assoc.h"
#include "winsmsc.h"
#include "nms.h"
#include "nmsmsgf.h"
#include "nmschl.h"
#include "nmsnmh.h"
#include "nmsscv.h"
#include "winsevt.h"
#include "winstmm.h"
#include "rplpull.h"
#include "rplpush.h"
#include "winsintf.h"
#include "lmaccess.h"
#include "winswriter.hpp"
/*
* Local Macro Declarations
*/
#define NMS_RANGE_SIZE 500
#define NMS_HW_SIZE 400
#define DBG_FILE_MAX_SIZE 1000000 //1 MB
#define DBG_TIME_INTVL_FOR_CHK 1800 //30 mts
/*
* Local Typedef Declarations
*/
/*
* Global Variable Definitions
*/
WINSTHD_POOL_T WinsThdPool; //thread pool for WINS
DWORD WinsTlsIndex; //TLS index for NBT threads
HANDLE NmsMainTermEvt; //For terminating the WINS service
HANDLE NmsTermEvt; //Termination event
HANDLE NmsCrDelNbtThdEvt;
CRITICAL_SECTION NmsTermCrtSec; //Critical Section guarding count of
//threads
//STATIC CRITICAL_SECTION sSvcCtrlCrtSec; //Critical Section guarding service
//controller initiated action
GENERIC_MAPPING NmsInfoMapping = {
STANDARD_RIGHTS_READ,
STANDARD_RIGHTS_WRITE,
STANDARD_RIGHTS_EXECUTE,
WINS_ALL_ACCESS
};
#ifdef WINSDBG
FUTURES("put all ctrs in a structure")
CRITICAL_SECTION sDbgCrtSec;
DWORD NmsGenHeapAlloc;
DWORD NmsDlgHeapAlloc;
DWORD NmsTcpMsgHeapAlloc;
DWORD NmsUdpHeapAlloc;
DWORD NmsUdpDlgHeapAlloc;
DWORD NmsQueHeapAlloc;
DWORD NmsAssocHeapAlloc;
DWORD NmsRpcHeapAlloc;
DWORD NmsRplWrkItmHeapAlloc;
DWORD NmsChlHeapAlloc;
DWORD NmsTmmHeapAlloc;
DWORD NmsCatchAllHeapAlloc;
DWORD NmsHeapAllocForList;
DWORD NmsGenHeapFree;
DWORD NmsDlgHeapFree;
DWORD NmsTcpMsgHeapFree;
DWORD NmsUdpHeapFree;
DWORD NmsUdpDlgHeapFree;
DWORD NmsQueHeapFree;
DWORD NmsAssocHeapFree;
DWORD NmsRpcHeapFree;
DWORD NmsRplWrkItmHeapFree;
DWORD NmsChlHeapFree;
DWORD NmsTmmHeapFree;
DWORD NmsCatchAllHeapFree;
DWORD NmsHeapCreate;
DWORD NmsHeapDestroy;
//
// Count of updates (to version number) made by WINS.
//
DWORD NmsUpdCtrs[WINS_NO_OF_CLIENTS][2][4][3][2];
DWORD NmsRplUpd;
DWORD NmsRplGUpd;
DWORD NmsNmhUpd;
DWORD NmsNmhGUpd;
DWORD NmsNmhRelUpd;
DWORD NmsNmhRelGUpd;
DWORD NmsScvUpd;
DWORD NmsScvGUpd;
DWORD NmsChlUpd;
DWORD NmsChlGUpd;
DWORD NmsRpcUpd;
DWORD NmsRpcGUpd;
DWORD NmsOthUpd;
DWORD NmsOthGUpd;
NMS_CTRS_T NmsCtrs;
CRITICAL_SECTION NmsHeapCrtSec;
STATIC volatile DWORD sReqDq = 0; //for testing only
STATIC volatile DWORD sRegReqDq = 0; //for testing only
STATIC volatile DWORD sReqQ = 0; //for testing only
STATIC volatile DWORD sRegReqQ = 0; //for testing only
STATIC volatile DWORD sRsp = 0; //for testing only
STATIC time_t sDbgLastChkTime;
volatile DWORD NmsRegReqQDropped = 0; //for testing only
extern DWORD NmsGenHeapAlloc;
#endif
PSECURITY_DESCRIPTOR pNmsSecurityDescriptor = NULL;
COMM_ADD_T NmsLocalAdd = {0}; //My own address
ULONG WinsDbg; //for debugging purposes. see winsdbg.h
/*
* NmsTotalTrmThdCnt -- The total number of threads that deal with NmsTermEvt
* event
* These are -- main thread, nbt threads, name challenge thd,
* scavenger thread, replication threads
*/
DWORD NmsTotalTrmThdCnt = 1; //set to 1 for the main thread
HANDLE GenBuffHeapHdl; //handle to heap for use for queue items
HANDLE NmsRpcHeapHdl; //handle to heap for use by rpc
DWORD NmsNoOfNbtThds = 0;
BOOL fNmsAbruptTerm = FALSE;
BOOL fNmsMainSessionActive = FALSE;
//
// Counter to indicate how many rpc calls that have to do with Jet are
// currently in progress
//
DWORD NmsNoOfRpcCallsToDb;
//
// This is set to TRUE to indicate that there are one or more threads
// that have active DB sessions but are not included in the count of
// threads with such sessions. When this is set to TRUE, the main thread
// will not call JetTerm (from within NmsDbRelRes) due to a limitation
// in Jet. We take a thread out of the count when it is involved in an
// activity that can take long since we do not want to hold up WINS termination
// for long. For example, the pull thread is taken out when it is trying
// to establish a connection.
//
BOOL fNmsThdOutOfReck = FALSE;
#if defined (DBGSVC) || TEST_DATA > 0
HANDLE NmsFileHdl = INVALID_HANDLE_VALUE;
HANDLE NmsDbgFileHdl = INVALID_HANDLE_VALUE;
#define QUERY_FAIL_FILE TEXT("wins.out")
#endif
VERS_NO_T NmsRangeSize = {0};
VERS_NO_T NmsHalfRangeSize = {0};
VERS_NO_T NmsVersNoToStartFromNextTime = {0};
VERS_NO_T NmsHighWaterMarkVersNo = {0};
/*
* Local Variable Definitions
*/
static BOOL sfHeapsCreated = FALSE;
static HANDLE sNbtThdEvtHdlArray[3]; //event array to wait on (NBT thread)
static BOOL fsBackupOnTerm = TRUE;
#if REG_N_QUERY_SEP > 0
STATIC HANDLE sOtherNbtThdEvtHdlArray[2]; //event array to wait on (NBT thread)
#endif
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHdl;
/*
* Local Function Prototype Declarations
*/
#if TEST_DATA > 0 || defined(DBGSVC)
STATIC BOOL
DbgOpenFile(
LPTSTR pFileNm,
BOOL fReopen
);
#endif
STATIC
STATUS
ProcessInit(
VOID
);
//
// Create a pool of NBT threads (Threads that service NBT requests)
//
STATIC
STATUS
CreateNbtThdPool(
IN DWORD NoOfThds,
IN LPTHREAD_START_ROUTINE NbtThdInitFn
);
//
// Initialize memory for use by NMS
//
STATIC
VOID
CreateMem(
VOID
);
//
// Startup function of an NBT thread
//
STATIC
DWORD
NbtThdInitFn(
IN LPVOID pThreadParam
);
#if REG_N_QUERY_SEP > 0
//
// Startup function of an NBT thread for registering
//
STATIC
DWORD
OtherNbtThdInitFn(
IN LPVOID pThreadParam
);
#endif
//
// Signal all threads inside WINS that have a session with the db engine
//
STATIC
VOID
SignalWinsThds (
VOID
);
//
// Update status for the benefit of the service controller
//
STATIC
VOID
UpdateStatus(
VOID
);
STATIC
VOID
CrDelNbtThd(
VOID
);
//
// Main function of WINS called by the thread that is created for
// listerning to the service controller
//
STATIC
VOID
WinsMain(
DWORD dwArgc,
LPTSTR *lpszArgv
);
//
// Responsible for the reinitialization of WINS
//
STATIC
VOID
Reinit(
WINSCNF_HDL_SIGNALED_E IndexOfHdlSignaled_e
);
//
// Responsible for initializing RPC
//
STATIC
BOOL
InitializeRpc(
VOID
);
STATIC
BOOL
InitSecurity(
VOID
);
STATIC
VOID
WrapUp(
DWORD ErrorCode,
BOOL fSvcSpecific
);
STATIC
VOID
GetMachineInfo(
VOID
);
//
// The main function
//
VOID __cdecl
main(
VOID
)
/*++
Routine Description:
This is the main function of the WINS server. It calls the
StartServiceCtrlDispatcher to connect the main thread of this process
(executing this function) to the Service Control Manager.
Arguments:
dwArgc - no. of arguments to this function
lpszArgv - list of pointers to the arguments
Externals Used:
WinsCnf
Return Value:
None
Error Handling:
Message is printed if DBG ids defined
Called by:
Startup code
Side Effects:
None
Comments:
None
--*/
{
//
//WINS server is a service in its own process
//
SERVICE_TABLE_ENTRY DispatchTable[] = {
{ WINS_SERVER, WinsMain },
{ NULL, NULL }
};
//
// Set WinsDbg if debugging is turned on
// Set RplEnabled if Replicator functionality is to be turned on
// Set ScvEnabled if Scavenging functionality is to be turned on
//
DBGINIT;
DBGCHK_IF_RPL_DISABLED;
DBGCHK_IF_SCV_DISABLED;
DBGCHK_IF_PERFMON_ENABLED;
#ifndef WINS_INTERACTIVE
if (! StartServiceCtrlDispatcher(DispatchTable) )
{
DBGPRINT0(ERR, "Main: StartServiceCtrlDispatcher Error\n");
return;
}
#else
WinsMain(1, (LPTSTR *)NULL);
#endif
return;
}
VOID
WinsMain(
DWORD dwArgc,
LPTSTR *lpszArgv
)
/*++
Routine Description:
This is the SERVICE_MAIN_FUNCTION of the WINS server. It
is called when the service controller starts the service.
Arguments:
dwArgc -- no of arguments
lpszArgc -- argument strings
Externals Used:
WinsCnf
NmsTermEvt
Return Value:
None
Error Handling:
Called by:
main()
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
#ifndef WINS_INTERACTIVE
DWORD Error;
#endif
HANDLE ThdEvtHdlArray[WINSCNF_E_NO_OF_HDLS_TO_MONITOR];
WINSCNF_HDL_SIGNALED_E IndexOfHdlSignaled_e;//index in the
//ThdEvtHdlArray of the
//handle that got signaled. Used as
//an arg to WinsMscWaitUntilSignaled
DWORD ExitCode = WINS_SUCCESS;
UNREFERENCED_PARAMETER(dwArgc);
UNREFERENCED_PARAMETER(lpszArgv);
/*
* Initialize the critical section that guards the
* NmsTotalTrmThdCnt count var.
*
* NOTE: The initialization of this critical section should occur
* prior to registering with the service controller. We are playing
* it safe just in case in the future SignalWinsThds gets called
* as part of the cleanup action due to an error that occurs right after
* we have made ourselves known to the service controller
*
* In any case, we must initialize it before calling NmsDbThdInit(). In
* short it must occue prior to the creation of any thread
*
*/
InitializeCriticalSection(&NmsTermCrtSec);
#ifndef WINS_INTERACTIVE
//
// Initialize all the status fields so that subsequent calls to
// SetServiceStatus need to only update fields that changed.
//
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCheckPoint = 1;
//
// Though 10000 is fine most of the times, for a slow overloaded system,
// it may not be enough. Let us be extra conservative and specify
// 60000 (60 secs). Most of the time is taken by Jet. In fact, in
// case the db is corrupted, we will do a restore which can take long.
// So, add another 60 secs for a grand total of 120000.
//
FUTURES("Specify 60 secs here and 60secs in nmsdb.c if Restore is to be")
FUTURES("attempted")
ServiceStatus.dwWaitHint = 120000;
ServiceStatus.dwWin32ExitCode = NO_ERROR;
ServiceStatus.dwServiceSpecificExitCode = 0;
// InitializeCriticalSection(&sSvcCtrlCrtSec);
//
// Initialize workstation to receive service requests by registering the
// control handler.
//
ServiceStatusHdl = RegisterServiceCtrlHandler(
WINS_SERVER,
NmsServiceControlHandler
);
if ( ServiceStatusHdl == (SERVICE_STATUS_HANDLE) 0) {
Error = GetLastError();
DBGPRINT1(ERR,"Wins: RegisterServiceCtrlHandler error = (%d)\n",
Error);
return;
}
//
// Tell Service Controller that we are start pending.
//
UpdateStatus();
#endif
#ifdef WINSDBG
InitializeCriticalSection(&sDbgCrtSec);
#endif
#ifdef WINSDBG
DBGSTART_PERFMON
fWinsCnfHighResPerfCntr =
QueryPerformanceFrequency(&LiWinsCnfPerfCntrFreq);
if (!fWinsCnfHighResPerfCntr)
{
printf("WinsMain: The hardware does not support the high resolution performance monitor\n");
}
else
{
printf("WinsMain: The hardware supports the high resolution performance monitor.\nThe FREQUENCY is (%d %d)\n",
LiWinsCnfPerfCntrFreq.HighPart,
LiWinsCnfPerfCntrFreq.LowPart
);
}
DBGEND_PERFMON
#endif
try {
/*
First and foremost, open (or create if non-existent) the log file
*/
WinsCnfInitLog();
//
// Call the initialization function for WINS. This function will
// make the WINS server operational.
//
#ifdef WINSDBG
IF_DBG(INIT_BRKPNT)
{
DbgUserBreakPoint();
}
#endif
RetStat = ProcessInit();
if ( RetStat != WINS_SUCCESS)
{
fNmsAbruptTerm = TRUE;
WrapUp(RetStat, TRUE);
DBGPRINT0(ERR, "WinsMain: Initialization Failed\n");
DBGPRINT0(ERR, "WINS Server has terminated\n");
return;
}
#ifndef WINS_INTERACTIVE
else
{
//
// Tell the service controller that we are up and running now
//
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN |
SERVICE_ACCEPT_PAUSE_CONTINUE;
UpdateStatus( );
if (fWinsCnfInitStatePaused)
{
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
UpdateStatus( );
}
}
//
// If Continue has been sent by the pull thread, it may have been
// sent while we were in the START_PENDING state. So, send it again.
// Sending it again is ok. We should also send it if we don't have
// any pnrs to pull from.
//
EnterCriticalSection(&RplVersNoStoreCrtSec);
if ((fRplPullContinueSent) || (WinsCnf.PullInfo.NoOfPushPnrs == 0))
{
WinsMscSendControlToSc(SERVICE_CONTROL_CONTINUE);
}
LeaveCriticalSection(&RplVersNoStoreCrtSec);
#endif
//
// Wait until we are told to stop or when the configuration changes.
//
//
// Initialize the array of handles on which this thread will
// wait.
//
// K&R C and ANSI C do not allow non-constant initialization of
// an array or a structure. C++ (not all compilers) allows it.
// So, we do it at run time.
//
ThdEvtHdlArray[WINSCNF_E_WINS_HDL] = WinsCnf.WinsKChgEvtHdl;
ThdEvtHdlArray[WINSCNF_E_PARAMETERS_HDL] = WinsCnf.ParametersKChgEvtHdl;
ThdEvtHdlArray[WINSCNF_E_PARTNERS_HDL] = WinsCnf.PartnersKChgEvtHdl;
ThdEvtHdlArray[WINSCNF_E_TERM_HDL] = NmsMainTermEvt;
FUTURES("I may want to create another thread to do all the initialization and")
FUTURES("wait on the registry change notification key. That way, the main")
FUTURES("thread will wait only on the TermEvt event. The justification for")
FUTURES("having another thread is debatable, so I am not doing so now ")
while(TRUE)
{
WinsMscWaitUntilSignaled (
ThdEvtHdlArray,
sizeof(ThdEvtHdlArray)/sizeof(HANDLE),
(LPDWORD)&IndexOfHdlSignaled_e,
TRUE
);
if (IndexOfHdlSignaled_e == WINSCNF_E_TERM_HDL)
{
DBGPRINT0(FLOW, "WinsMain: Got termination signal\n");
//
// Wrap up
//
WrapUp(ERROR_SUCCESS, FALSE);
break;
}
else // registry change notification received. Do reinitialization
{
//
// reinitialize the WINS server according to changes in the
// registry
//
Reinit(IndexOfHdlSignaled_e);
}
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsMain");
//
// we received an exception. Set the fNmsAbruptTerm so that
// JetTerm is not called.
//
fNmsAbruptTerm = TRUE;
//
// Have an exception handler around this call just in case the
// WINS or the system is really sick and Wrapup also generates
// an exception. We are not bothered about performance at this
// point.
//
FUTURES("Check into restructuring the exception handlers in a better way")
try {
WrapUp(GetExceptionCode(), TRUE);
}
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WinsMain");
}
ExitCode = GetExceptionCode();
WINSEVT_LOG_M(ExitCode, WINS_EVT_ABNORMAL_SHUTDOWN);
}
#ifndef WINS_INTERACTIVE
//
// If it is not one of WINS specific codes, it may be a WIN32 api
// or NTstatus codes. Just in case it is an NTStatus codes, convert
// it to a wins32 code since that is what the Service Controller likes.
//
if ((ExitCode & WINS_FIRST_ERR_STATUS) != WINS_FIRST_ERR_STATUS)
{
ExitCode = RtlNtStatusToDosError((NTSTATUS)ExitCode);
ServiceStatus.dwWin32ExitCode = ExitCode;
ServiceStatus.dwServiceSpecificExitCode = 0;
}
else
{
ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
ServiceStatus.dwServiceSpecificExitCode = ExitCode;
}
//
// We are done with cleaning up. Tell Service Controller that we are
// stopped.
//
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
UpdateStatus();
#endif
DBGPRINT0(ERR, "WINS Server has terminated\n");
return;
} // end of WinsMain()
STATUS
ProcessInit(
VOID
)
/*++
Routine Description:
This is the function that initializes the WINS. It is executed in
the main thread of the process
Arguments:
None
Externals Used:
None
Called by:
WinsMain()
Comments:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
--*/
{
DWORD NoOfThds;
/*
* Initialize the Critical Section used for name registrations and
* refreshes
*/
InitializeCriticalSection(&NmsNmhNamRegCrtSec);
//
// Initialize the critical section that protects the statistics
// var. (WinsIntfStat). This needs to be done here before any
// thread is created because various threads call WinsIntfSetTime
// which uses this critical section
//
InitializeCriticalSection(&WinsIntfCrtSec);
InitializeCriticalSection(&WinsIntfPotentiallyLongCrtSec);
InitializeCriticalSection(&WinsIntfNoOfUsersCrtSec);
#if TEST_DATA > 0
//
// Set WinsDbg so that we don't miss any printfs until we read
// the registry
//
WinsDbg = DBG_ERR | DBG_EXC | DBG_FLOW | DBG_DET | DBG_HEAP_CRDL |
DBG_HEAP_CNTRS;
(VOID)DbgOpenFile(QUERY_FAIL_FILE, FALSE);
#endif
#if defined(DBGSVC) || defined(WINS_INTERACTIVE)
//#if defined(DBGSVC) && !defined(WINS_INTERACTIVE)
#ifdef DBG
(VOID)time(&sDbgLastChkTime);
(VOID)DbgOpenFile(WINSDBG_FILE, FALSE);
#endif
#endif
//
// Initialize the Counter that keeps track of the highest version
// number registered by this server
//
WINS_ASSIGN_INT_TO_LI_M(NmsNmhMyMaxVersNo, 1);
NmsRangeSize.QuadPart = NMS_RANGE_SIZE;
NmsHalfRangeSize.QuadPart = NMS_HW_SIZE;
NmsVersNoToStartFromNextTime.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize);
NmsHighWaterMarkVersNo.QuadPart = LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize);
//
// The lowest version to start scavenging from
//
NmsScvMinScvVersNo = NmsNmhMyMaxVersNo;
//
// Initialize the global var. to be used to increment/decrement the
// above counter by 1.
//
WINS_ASSIGN_INT_TO_LI_M(NmsNmhIncNo, 1);
/*
* Create Memory Heaps used by the Name Space Manager
*/
CreateMem();
/*
* Allocate a TLS index so that each thread can set and get
* thread specific info
*/
WinsTlsIndex = TlsAlloc();
if (WinsTlsIndex == 0xFFFFFFFF)
{
DBGPRINT1(ERR,
"Init: Unable to allocate TLS index. Error = (%d)\n",
GetLastError()
);
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
}
//
// Initialize the thread count to 1 (to account for this thread)
//
WinsThdPool.ThdCount = 1;
//
// Allocate an array of 100 slots to store version numbers
//
RplPullAllocVersNoArray( &pRplPullOwnerVersNo, RplPullMaxNoOfWins );
//
// Store local machine's ip address in NmsLocalAdd. We need to
// do this before calling WinsCnfInitConfig so that we can
// make sure that this WINS is not listed as its own partner
// in the registry
//
if (ECommGetMyAdd(&NmsLocalAdd) != WINS_SUCCESS)
{
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_BAD_WINS_ADDRESS);
return(WINS_FAILURE);
}
/*
* Read the configuration information from the registry
* into in-memory data structures
*/
WinsCnfInitConfig();
// if (fWinsCnfInitStatePaused)
// {
// NtClose(WinsCnfNbtHandle);
// }
//
// Get machine information
//
GetMachineInfo();
//
// Update Status
//
/*
* Initialize the Database Manager
*/
if (NmsDbInit() != WINS_SUCCESS)
{
return(WINS_FAILURE);
}
#ifndef WINS_INTERACTIVE
//
// Though 3000 should be ok, let us be extra conservative and
// specify 30000. Actually, if DNS is down, it takes around
// 35 secs for timeout (rpc over tcpip may result in query to
// WINS if query WINS for resolution check box is checked). So,
// let us add another 30 secs for that for a total of 60000
// Throw in another 30 secs for good measure to arrive at a grand
// total of 120 secs.
//
ServiceStatus.dwWaitHint = 120000;
ServiceStatus.dwCheckPoint++;
UpdateStatus(); //inform the service control manager
#endif
//
// NOTE: The value of NmsNmhMyMaxVersNo may have been changed by
// NmsDbInit()
//
// If we did not find the version counter value for next time in
// the registry or if the high water mark is lower than our
// max. version number, adjust it and the next time start version
// number and write it to the registry (since we are about to start
// the worker threads).
//
if (!fWinsCnfReadNextTimeVersNo || LiLtr(NmsHighWaterMarkVersNo,
NmsNmhMyMaxVersNo))
{
NmsVersNoToStartFromNextTime.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsRangeSize);
NmsHighWaterMarkVersNo.QuadPart =
LiAdd(NmsNmhMyMaxVersNo, NmsHalfRangeSize);
WinsCnfWriteReg(&fWinsCnfReadNextTimeVersNo);
}
/*
* Create the two event variables used for termination
*/
//
// NmsTermEvt is signaled by this main thread to signal all those
// WINS threads that have db session to wrap up their sessions and
// terminate
//
WinsMscCreateEvt(
TEXT("WinsTermEvt"),
TRUE, //Manual Reset
&NmsTermEvt
);
/*
* NmsMainTermEvt -- This event is signaled by the service controller
* or by another thread in the WINS server to request termination.
*/
WinsMscCreateEvt(
TEXT("WinsMainTermEvt"),
FALSE, //Auto Reset
&NmsMainTermEvt
);
/*
* Do Static Initialization if required
*/
if(WinsCnf.fStaticInit)
{
//
// Do the initialization and deallocate the memory
//
if (WinsCnf.pStaticDataFile != NULL)
{
(VOID)WinsPrsDoStaticInit(
WinsCnf.pStaticDataFile,
WinsCnf.NoOfDataFiles,
TRUE //do it asynchronously
);
//
// No need to deallocate memory for data file.
// It should have been freed by WinsPrsDoStaticInit
//
}
}
/*
* Create the nbt request thread pool
*/
//
// If the user has not specified the number of threads, use the
// processor count to determine the same, else use the value given
// by user.
//
if (WinsCnf.MaxNoOfWrkThds == 0)
{
NoOfThds = WinsCnf.NoOfProcessors + 1;
}
else
{
NoOfThds = WinsCnf.MaxNoOfWrkThds == 1 ? 2 : WinsCnf.MaxNoOfWrkThds;
}
CreateNbtThdPool(
NoOfThds,
// WinsCnf.MaxNoOfWrkThds == 1 ? 2 : WinsCnf.MaxNoOfWrkThds,
//WINSTHD_DEF_NO_NBT_THDS,
NbtThdInitFn
);
/*
*Initialize the name challenge manager
*/
NmsChlInit();
/*
* Initialize the Timer Manager
*/
WinsTmmInit();
/*
*Initialize the Replicator. Initialize it before initializing
* the comm threads or the rpc threads. This is because, the
* comm threads and the rpc threads can create the Push thread
* if it is not-existent. fRplPushThdExists is set to TRUE or
* FALSE by this function without the protection of a critical
* section
*/
ERplInit();
/*
*Initialize the Comm. subsystem
*/
ECommInit();
/*
* Initialize the scavenger code
*/
NmsScvInit();
/*
* All threads have been created.
*/
// We can not mark state as steady state until all threads are in
// steady state
FUTURES("Mark state as STEADY STATE only after the above is true")
//
// Mark state as steady state. This is actually a PSEUDO steady
// state since all the threads may not have initialized yet. This
// will however do for rpc threads that need to know whether the
// critical sections have been initialized or not
//
//
// NOTE: there is no need to enter a critical section here even
// though there are other threads (rpc threads) reading this since
// if they find the value to be anything other than RUNNING
// they will return a failure which is ok for the minute time window
// where concurrent write and reads are going on
//
WinsCnf.State_e = WINSCNF_E_RUNNING;
//
// Do all RPC related initialization.
//
if (InitializeRpc() == FALSE)
{
DBGPRINT0(ERR, "Init: Rpc not initialized properly. Is Rpc service up\n");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_RPC_NOT_INIT);
}
NmsDbCloseTables();
//
// Log an informational message
//
WinsIntfSetTime(NULL, WINSINTF_E_WINS_START);
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_WINS_OPERATIONAL);
DBGPRINT0(DET, "WINS: Operational\n");
return(WINS_SUCCESS);
}
VOID
ENmsHandleMsg(
IN PCOMM_HDL_T pDlgHdl,
IN MSG_T pMsg,
IN MSG_LEN_T MsgLen
)
/*++
Routine Description:
This function queues the message either on the nbt request queue or on
the nbt response queue.
Arguments:
pDlgHdl - Dialogue handle
pMsg - Ptr to message to process
MsgLen - Message length
Externals Used:
None
Called by:
ParseMsg in comm.c
Comments:
None
Return Value:
None
--*/
{
DWORD fRsp;
BYTE Opcode = *(pMsg + 2);
STATUS RetStat;
/*
* Check whether the message is a request or a response
*/
fRsp = NMS_RESPONSE_MASK & Opcode;
if (!fRsp)
{
if ((WinsCnf.State_e == WINSCNF_E_PAUSED) || fWinsCnfInitStatePaused)
{
//
// Don't even let the queries go through since
// the InitTimePaused state is meant for building
// up the db while the backup handles the load
// This way clients time out and try the backup.
// If we let queries through, clients may get
// back -ve query responses and will not go to
// the backup for the name resolution
//
ECommFreeBuff(pMsg);
ECommEndDlg(pDlgHdl);
return;
}
DBGPRINT0(FLOW,
"ENmsHandleMsg: Listener thread: queuing a work item\n");
#if REG_N_QUERY_SEP > 0
if (((NMS_OPCODE_MASK & Opcode) >> 3) == NMSMSGF_E_NAM_QUERY)
{
QueInsertNbtWrkItm(pDlgHdl, pMsg, MsgLen);
#ifdef WINSDBG
sReqQ++;
#endif
}
else
{
RetStat = QueInsertOtherNbtWrkItm(pDlgHdl, pMsg, MsgLen);
#ifdef WINSDBG
sRegReqQ++;
#endif
}
#else
QueInsertNbtWrkItm(pDlgHdl, pMsg, MsgLen);
sReqQ++;
#endif
}
else
{
DBGPRINT0(FLOW,
"UDP listener thread: queuing a response work item\n");
QueInsertChlRspWrkItm(pDlgHdl, pMsg, MsgLen);
#ifdef WINSDBG
sRsp++;
#endif
}
return;
}
VOID
CreateMem(
VOID
)
/*++
Routine Description:
This function creates the heap that is used for allocating work
items for the NBT work queues. It also creates a heap for general
allocation.
Arguments:
None
Externals Used:
GenBuffHeapHdl, QueBuffHeapHdl
Return Value:
None
Error Handling:
Called by:
Init
Side Effects:
Comments:
None
--*/
{
#ifdef WINSDBG
InitializeCriticalSection(&NmsHeapCrtSec);
#endif
/*
* Create heap for general allocation of memory
*/
DBGPRINT0(HEAP_CRDL, "CreateMem: Gen. Buff Heap\n");
GenBuffHeapHdl = WinsMscHeapCreate(
0, /*to have mutual exclusion */
GEN_INIT_BUFF_HEAP_SIZE
);
/*
* Create heap for allocating nbt work items
*/
DBGPRINT0(HEAP_CRDL, "CreateMem: Que. Buff Heap\n");
QueBuffHeapHdl = WinsMscHeapCreate(
0, /*to have mutual exclusion */
QUE_INIT_BUFF_HEAP_SIZE
);
/*
* Create heap for rpc use
*/
DBGPRINT0(HEAP_CRDL, "CreateMem: Rpc. Buff Heap\n");
NmsRpcHeapHdl = WinsMscHeapCreate(
0, /*to have mutual exclusion */
RPC_INIT_BUFF_HEAP_SIZE
);
//
// Let us set the flag looked at by WrapUp()
//
sfHeapsCreated = TRUE;
return;
}
STATUS
CreateNbtThdPool(
IN DWORD NoOfThds,
IN LPTHREAD_START_ROUTINE NbtThdInitFn
)
/*++
Routine Description:
This function creates the nbt request thread pool
Arguments:
NoOfThds -- No. of threads to create
NbtThdInitFn -- Initialization function for the threads
Externals Used:
QueNbtWrkQueHd, sNbtThdEvtHdlArray
Called by:
Init
Comments:
None
Return Value:
Success status codes -- Function should never return for a normal
thread. It returns WINS_SUCCESS for an
overload thread
Error status codes -- WINS_FATAL_ERR
--*/
{
DWORD i; //counter for the number of threads
DWORD Error;
PLIST_ENTRY pHead;
#if REG_N_QUERY_SEP > 0
pHead = &QueOtherNbtWrkQueHd.Head;
/*
* Initialize the critical section that protects the
* nbt req. queue
*/
InitializeCriticalSection(&QueOtherNbtWrkQueHd.CrtSec);
/*
* Initialize the listhead for the nbt request queue
*/
InitializeListHead(pHead);
/*
* Create an auto-reset event for the nbt request queue
*/
WinsMscCreateEvt(
NULL, //create without name
FALSE, //auto-reset var.
&QueOtherNbtWrkQueHd.EvtHdl
);
#endif
pHead = &QueNbtWrkQueHd.Head;
/*
* Initialize the critical section that protects the
* nbt req. queue
*/
InitializeCriticalSection(&QueNbtWrkQueHd.CrtSec);
/*
* Initialize the listhead for the nbt request queue
*/
InitializeListHead(pHead);
/*
* Create an auto-reset event for the nbt request queue
*/
WinsMscCreateEvt(
NULL, //create without name
FALSE, //auto-reset var.
&QueNbtWrkQueHd.EvtHdl
);
/*
* Create an auto-reset event for the dynamic creation/deletion of
* Nbt threads.
*/
WinsMscCreateEvt(
NULL, //create without name
FALSE, //auto-reset var.
&NmsCrDelNbtThdEvt
);
/*
* Initialize the array of handles on which each nbt thread will
* wait.
*/
sNbtThdEvtHdlArray[0] = QueNbtWrkQueHd.EvtHdl; //work queue event
//var
sNbtThdEvtHdlArray[1] = NmsCrDelNbtThdEvt; //
sNbtThdEvtHdlArray[2] = NmsTermEvt; //termination event var
#if REG_N_QUERY_SEP > 0
/*
* Initialize the array of handles on which each nbt reg. thread will
* wait.
*/
sOtherNbtThdEvtHdlArray[0] = QueOtherNbtWrkQueHd.EvtHdl; //work queue event
//var
sOtherNbtThdEvtHdlArray[1] = NmsTermEvt; //termination event var
#endif
/*
* Create the nbt request handling threads
*/
for (i=0; i < NoOfThds -1; i++)
{
#if REG_N_QUERY_SEP > 0
DBGPRINT1(DET, "CreateNbtThdPool: Creating query thread no (%d)\n", i);
#else
DBGPRINT1(DET, "NbtThdInitFn: Creating worker thread no (%d)\n", i);
#endif
/*
Create an NBT req thread
*/
WinsThdPool.NbtReqThds[i].ThdHdl = CreateThread(
NULL, /*def sec. attributes*/
0, /*use default stack size*/
NbtThdInitFn,
NULL, /*no arg*/
0, /*run it now*/
&WinsThdPool.NbtReqThds[i].ThdId
);
if (NULL == WinsThdPool.NbtReqThds[i].ThdHdl)
{
Error = GetLastError();
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_WRK_THD);
}
else
{
WinsThdPool.NbtReqThds[i].fTaken = TRUE;
NmsNoOfNbtThds++;
}
}
#if REG_N_QUERY_SEP > 0
DBGPRINT1(DET, "NbtThdInitFn: Creating reg/rel thread no (%d)\n", i);
/*
Create an NBT req thread
*/
WinsThdPool.NbtReqThds[i].ThdHdl = CreateThread(
NULL, /*def sec. attributes*/
0, /*use default stack size*/
OtherNbtThdInitFn,
NULL, /*no arg*/
0, /*run it now*/
&WinsThdPool.NbtReqThds[i].ThdId
);
if (NULL == WinsThdPool.NbtReqThds[i].ThdHdl)
{
Error = GetLastError();
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_WRK_THD);
}
else
{
WinsThdPool.NbtReqThds[i].fTaken = TRUE;
NmsNoOfNbtThds++;
}
#endif
/*
* if no thread could be created, there is something really wrong
*/
if (NmsNoOfNbtThds == 0)
{
WINSEVT_LOG_M(Error, WINS_EVT_CANT_INIT);
return(WINS_FATAL_ERR);
}
WinsThdPool.ThdCount += NmsNoOfNbtThds;
return(WINS_SUCCESS);
}
DWORD
NbtThdInitFn(
IN LPVOID pThreadParam
)
/*++
Routine Description:
This function is the startup function of threads created
for the nbt request thread pool
Arguments:
pThreadParam - Input argument which if present indicates that this
is an overload thread
Externals Used:
sNbtThdEvtHdlArray
Called by:
CreateNbtThdPool
Comments:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
--*/
{
COMM_HDL_T DlgHdl;
MSG_T pMsg;
MSG_LEN_T MsgLen;
PNBT_REQ_WRK_ITM_T pWrkItm;
DWORD ArrInd; //Index of hdl in hdl array
try {
/*
* Initialize the thread with the database
*/
NmsDbThdInit(WINS_E_NMSNMH);
#if REG_N_QUERY_SEP > 0
DBGMYNAME("Nbt Query Thread");
#else
DBGMYNAME("Nbt Thread");
#endif
//
// The worker thread is more important that all other threads.
//
// Set the priority of this thread to one level above what it is
// for WINS.
//
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
/*
* if thread param is NON-NULL, then it means that this is
* an overload thread
*/
if (pThreadParam != NULL)
{
//
//Exract the dlg handle, message and msglen from work item
//
pWrkItm = pThreadParam;
DlgHdl = pWrkItm->DlgHdl;
pMsg = pWrkItm->pMsg;
MsgLen = pWrkItm->MsgLen;
/*
* process the request
*/
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
/*
* Loop until there are no more requests to process in
* the NBT queue.
*/
while(TRUE)
{
if ( QueRemoveNbtWrkItm(
&DlgHdl,
&pMsg,
&MsgLen) == WINS_NO_REQ
)
{
break;
}
else
{
NmsDbOpenTables(WINS_E_NMSNMH);
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
NmsDbCloseTables();
}
}
}
else // this is a normal thread
{
LOOP:
try {
/*
*loop forever
*/
while(TRUE)
{
/*
* Block until signaled
*/
WinsMscWaitUntilSignaled(
sNbtThdEvtHdlArray,
sizeof(sNbtThdEvtHdlArray)/sizeof(HANDLE), //no of events
//in array
&ArrInd,
FALSE
);
if (ArrInd == 0)
{
/*
Loop until there are no more requests to process in
the NBT queue.
*/
while(TRUE)
{
if (
QueRemoveNbtWrkItm(
&DlgHdl,
&pMsg,
&MsgLen) == WINS_NO_REQ
)
{
break;
}
else
{
#ifdef WINSDBG
++sReqDq;
#endif
// DBGPRINT1(SPEC, "Nms: Dequeued Name Query Request no = (%d)\n",
// sReqDq);
DBGPRINT0(FLOW, "NBT thread: Dequeued a Request\n");
NmsDbOpenTables(WINS_E_NMSNMH);
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
NmsDbCloseTables();
} // end of else
} // end of while (TRUE) for getting requests from the queue
} // end of if (signaled for name request handling)
else
{
//
// If signaled for creating/deleting threads, do so
//
if (ArrInd == 1)
{
CrDelNbtThd();
}
else
{
//
// If Array Index indicates termination event, terminate the
// the thread
//
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
}
}
} // end of while (TRUE) (never ending loop)
} // end of inner try {..}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINTEXC("NbtThdInitFn: Nbt Thread \n");
//
// If ExcCode indicates 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)
{
WINSEVT_LOG_M(ExcCode, WINS_EVT_WRK_EXC);
}
}
}
else
{
WINSEVT_LOG_M(ExcCode, WINS_EVT_WRK_EXC);
}
}
goto LOOP;
} // end of else (this is a normal thread)
} // end of outer try block
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("NbtThdInitFn: Nbt Thread exiting abnormally\n");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_WRK_ABNORMAL_SHUTDOWN);
//
// If NmsDbThdInit() results in an exception, it is possible
// that the session has not yet been started. Passing
// WINS_DB_SESSION_EXISTS however is ok
//
//
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
}
/*
*Only an overload thread should reach this return
*/
ASSERT(pThreadParam != NULL);
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
return(WINS_SUCCESS);
}
#if REG_N_QUERY_SEP > 0
DWORD
OtherNbtThdInitFn(
IN LPVOID pThreadParam
)
/*++
Routine Description:
This function is the startup function of threads created
for the nbt request thread pool
Arguments:
pThreadParam - Input argument which if present indicates that this
is an overload thread
Externals Used:
sNbtThdEvtHdlArray
Called by:
CreateNbtThdPool
Comments:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
--*/
{
COMM_HDL_T DlgHdl;
MSG_T pMsg;
MSG_LEN_T MsgLen;
PNBT_REQ_WRK_ITM_T pWrkItm;
DWORD ArrInd; //Index of hdl in hdl array
try {
/*
* Initialize the thread with the database
*/
NmsDbThdInit(WINS_E_NMSNMH);
DBGMYNAME("Nbt Reg Thread");
//
// The worker thread is more important that all other threads.
//
// Set the priority of this thread to one level above what it is
// for WINS.
//
// SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
/*
* if thread param is NON-NULL, then it means that this is
* an overload thread
*/
if (pThreadParam != NULL)
{
//
//Exract the dlg handle, message and msglen from work item
//
pWrkItm = pThreadParam;
DlgHdl = pWrkItm->DlgHdl;
pMsg = pWrkItm->pMsg;
MsgLen = pWrkItm->MsgLen;
/*
* process the request
*/
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
/*
* Loop until there are no more requests to process in
* the NBT queue.
*/
while(TRUE)
{
if ( QueRemoveOtherNbtWrkItm(
&DlgHdl,
&pMsg,
&MsgLen) == WINS_NO_REQ
)
{
break;
}
else
{
NmsDbOpenTables(WINS_E_NMSNMH);
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
NmsDbCloseTables();
}
}
}
else // this is a normal thread
{
LOOP:
try {
/*
*loop forever
*/
while(TRUE)
{
/*
* Block until signaled
*/
WinsMscWaitUntilSignaled(
sOtherNbtThdEvtHdlArray,
sizeof(sOtherNbtThdEvtHdlArray)/sizeof(HANDLE), //no of events
//in array
&ArrInd,
FALSE
);
if (ArrInd == 0)
{
/*
Loop until there are no more requests to process in
the NBT queue.
*/
while(TRUE)
{
if (
QueRemoveOtherNbtWrkItm(
&DlgHdl,
&pMsg,
&MsgLen) == WINS_NO_REQ
)
{
break;
}
else
{
#ifdef WINSDBG
++sRegReqDq;
#endif
// DBGPRINT1(SPEC, "Nms: Dequeued Name Reg/Rel Request no = (%d)\n",
// sRegReqDq);
DBGPRINT0(FLOW, "NBT thread: Dequeued a Request\n");
NmsDbOpenTables(WINS_E_NMSNMH);
NmsMsgfProcNbtReq(
&DlgHdl,
pMsg,
MsgLen
);
NmsDbCloseTables();
} // end of else
} // end of while (TRUE) for getting requests from the queue
} // end of if (signaled for name request handling)
else
{
//
// If Array Index indicates termination event, terminate the
// the thread
//
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
}
} // end of while (TRUE) (never ending loop)
} // end of inner try {..}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINTEXC("OtherNbtThdInitFn: Nbt Reg/Rel Thread \n");
//
// If ExcCode indicates 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)
{
WINSEVT_LOG_M(ExcCode, WINS_EVT_WRK_EXC);
}
}
}
}
goto LOOP;
} // end of else (this is a normal thread)
} // end of outer try block
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("NbtThdInitFn: Nbt Reg Thread exiting abnormally\n");
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_WRK_ABNORMAL_SHUTDOWN);
//
// If NmsDbThdInit() results in an exception, it is possible
// that the session has not yet been started. Passing
// WINS_DB_SESSION_EXISTS however is ok
//
//
WinsMscTermThd(WINS_FAILURE, WINS_DB_SESSION_EXISTS);
}
/*
*Only an overload thread should reach this return
*/
ASSERT(pThreadParam != NULL);
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
return(WINS_SUCCESS);
}
#endif
VOID
SignalWinsThds (
VOID
)
/*++
Routine Description:
This function is called to terminate all threads in the process.
Arguments:
None
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsMain()
Side Effects:
Comments:
None
--*/
{
time_t ThdTermStartTime;
DBGENTER("SignalWinsThds\n");
//
// Close the udp and tcp sockets
//
WinsCnf.State_e = WINSCNF_E_TERMINATING;
//
// Signal the manual-reset event variable NmsTermEvt. This
// should signal all threads that deal with the db
//
// makes sure to set the Nbt handle to NULL to avoid NtClose() to be called from ECommGetMyAdd
// on a closed handle - this would result in raising an exception. (bug #86768)
//
NtClose(WinsCnfNbtHandle);
WinsCnfNbtHandle = NULL;
SetEvent(NmsTermEvt);
#if USENETBT == 0
closesocket(CommUdpPortHandle);
#else
#if MCAST > 0
CommSendMcastMsg(COMM_MCAST_WINS_DOWN);
CommLeaveMcastGrp();
closesocket(CommUdpPortHandle);
#endif
#endif
//
// Just in case we are terminating before having created the socket
//
if (CommTcpPortHandle != INVALID_SOCKET)
{
CommDisc(CommTcpPortHandle, FALSE);
}
#define FIVE_MTS 300 //seconds
//
// This is an infinite loop.
//
(VOID)time(&ThdTermStartTime);
while(TRUE)
{
time_t CurrTime;
DWORD TrmThdCnt;
//
// If all threads that deal with the db have terminated
// break out of the loop.
//
// It is possible that WINS is terminating during
// initialization itself. The Counter is incremented
// in NmsDbThdInit() as each thread that has to deal with the
// db engine initializes itself with it.
//
// If NmsTotalTrmThdCnt is <=1 break. The count can go
// lower than 1 if a db thread is terminating without having
// incremented the above counter
//
EnterCriticalSection(&NmsTermCrtSec);
TrmThdCnt = NmsTotalTrmThdCnt;
LeaveCriticalSection(&NmsTermCrtSec);
if ((TrmThdCnt <= 1) || fNmsAbruptTerm)
{
break;
}
if (((CurrTime = time(NULL)) - ThdTermStartTime) < FIVE_MTS)
{
//
// Wait until signaled (when all threads have or are about
// to terminate)
//
DBGPRINT1(DET, "SignalWinsThds: Thd count left (%d)\n", TrmThdCnt);
WinsMscWaitInfinite(NmsMainTermEvt);
}
else
{
DBGPRINT1(ERR, "SignalWinsThds: Thd count left (%d); BREAKING OUT DUE TO ONE HOUR DELAY\n", TrmThdCnt);
WINSEVT_LOG_M(WINS_EVT_TERM_DUE_TIME_LMT, TrmThdCnt);
break;
}
}
//
// End the Db Session for this thread (main thread).
//
if (fNmsMainSessionActive)
{
NmsDbEndSession();
}
FUTURES("Check state of WINS. If Rpc has been initialized or maybe even")
FUTURES("otherwise, call RpcEpUnRegister")
DBGLEAVE("SignalWinsThds\n");
return;
} // SignalWinsThds()
VOID
UpdateStatus(
VOID
)
/*++
Routine Description:
This function updates the workstation service status with the Service
Controller.
Arguments:
None.
Return Value:
None
--*/
{
DWORD Status = NO_ERROR;
if (ServiceStatusHdl == (SERVICE_STATUS_HANDLE) 0) {
DBGPRINT0(ERR, "WINS Server: Cannot call SetServiceStatus, no status handle.\n");
return;
}
if (! SetServiceStatus(ServiceStatusHdl, &ServiceStatus))
{
Status = GetLastError();
DBGPRINT1(ERR, " WINS Server: SetServiceStatus error %lu\n", Status);
}
return;
} //UpdateStatus()
VOID
NmsServiceControlHandler(
IN DWORD Opcode
)
/*++
Routine Description:
This is the service control handler of the Wins service.
Arguments:
Opcode - Supplies a value which specifies the action for the
service to perform.
Return Value:
None.
--*/
{
BOOL fRet = FALSE;
// EnterCriticalSection(&sSvcCtrlCrtSec);
try {
switch (Opcode)
{
case SERVICE_CONTROL_SHUTDOWN:
//
// Backup can take a long time to execute. If the service
// controller kills us in the middle, it will mess up the
// backup. So, let us disable it.
//
fsBackupOnTerm = FALSE;
case SERVICE_CONTROL_STOP:
DBGPRINT1(DET, "NmsServiceControlHandler: %s Signal received\n", Opcode == SERVICE_CONTROL_STOP ? "STOP" : "SHUTDOWN");
if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING)
{
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint = 1;
//
// We keep a high wait time (5 mts) to take care of the
// case where the replicator pull thread is busy trying
// to set up communication with partners that are not
// up. Tcpip stack takes around a minute and a half to come
// back in case of failure. Also, WINS might have to do
// backup on termination.
//
ServiceStatus.dwWaitHint = 300000;
//
// Send the status response.
//
UpdateStatus();
WINSEVT_LOG_INFO_M(WINS_SUCCESS, WINS_EVT_ORDERLY_SHUTDOWN);
//
// Signal the main thread
//
if (! SetEvent(NmsMainTermEvt))
{
//
// Problem with setting event to terminate Workstation
// service.
//
DBGPRINT1(ERR,
"Service Control Handler: Error signaling NmsMainTermEvt %lu\n",
GetLastError());
}
fRet = TRUE;
}
break;
case SERVICE_CONTROL_PAUSE:
if (WinsCnf.State_e == WINSCNF_E_RUNNING)
{
DBGPRINT0(DET,"NmsServiceControlHandler: Pausing WINS\n");
WinsCnf.State_e = WINSCNF_E_PAUSED;
// NtClose(WinsCnfNbtHandle);
// SndQueryToLocalNetbt();
//CommDisc(CommTcpPortHandle);
}
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
//
// If the state is paused as a result of a pause from the sc
// or if it is paused as a result of a registry directive,
// we need to unpause it
//
if (
(WinsCnf.State_e == WINSCNF_E_PAUSED)
||
fWinsCnfInitStatePaused
)
{
//
// If paused as a result of sc directive, open nbt since
// we closed it earlier. Note: We can have a case where
// WINS was init time paused and then it got a pause from
// sc. The state would have then changed from RUNNING to
// PAUSED.
//
if (fWinsCnfInitStatePaused)
{
fWinsCnfInitStatePaused = FALSE;
}
// CommCreateUdpThd();
// CommCreateTcpThd();
WinsCnf.State_e = WINSCNF_E_RUNNING;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
}
break;
case SERVICE_CONTROL_INTERROGATE:
break;
//
// Service specific command
//
case WINS_ABRUPT_TERM:
fNmsAbruptTerm = TRUE;
//
// Signal the main thread
//
if (! SetEvent(NmsMainTermEvt))
{
//
// Problem with setting event to terminate Workstation
// service.
//
DBGPRINT1(ERR,
"Service Control Handler: Error signaling NmsMainTermEvt for abrupt termination. Error = %lu\n",
GetLastError());
}
fRet = TRUE;
break;
default:
break;
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("NmsServiceControlHandler");
}
// LeaveCriticalSection(&sSvcCtrlCrtSec);
if (!fRet)
{
//
// Send the status response.
//
UpdateStatus();
}
return;
} //NmsServiceControlHandler
VOID
Reinit(
WINSCNF_HDL_SIGNALED_E IndexOfHdlSignaled_e
)
/*++
Routine Description:
This function is called whenever the configuration of the WINS changes.
Arguments:
None
Externals Used:
WinsCnf
Return Value:
None
Error Handling:
Called by:
WinsMain
Side Effects:
Comments:
--*/
{
PWINSCNF_CNF_T pWinsCnf;
DBGENTER("Reinit\n");
try {
if (IndexOfHdlSignaled_e == WINSCNF_E_WINS_HDL)
{
// request notification for any subsequent changes (we have
// to request changes every time we get a notification if we
// want notification of further changes).
//
WinsCnfAskToBeNotified(WINSCNF_E_WINS_KEY);
//
// Maybe a key has been created or deleted
//
WinsCnfOpenSubKeys();
DBGLEAVE("Reinit\n");
return;
}
//
// If either PULL or PUSH information has changed, copy the
// read the new data from the registry and inform the
// replicator
//
if (IndexOfHdlSignaled_e == WINSCNF_E_PARTNERS_HDL)
{
WinsCnfAskToBeNotified(WINSCNF_E_PARTNERS_KEY);
//
// Allocate the WinsCnf structure
//
WinsMscAlloc(
sizeof(WINSCNF_CNF_T),
&pWinsCnf
);
//
// Read the Partner information
//
WinsCnfReadPartnerInfo(pWinsCnf);
//
// Copy some (not all) of the configuration information into
// the global WinsCnf structure. Sanity check of the
// parameters will be done by this function and the
// scavenger thread will be signaled if required.
//
WinsCnfCopyWinsCnf(WINS_E_RPLPULL, pWinsCnf);
//
// 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_CONFIG,
NULL, //no dlg handle
NULL, //no msg
0, //msg len
pWinsCnf, //client ctx
pWinsCnf->MagicNo
);
DBGLEAVE("Reinit\n");
return;
}
//
// Parameters related to WINS's configuration (nothing to do with
// how it interacts with its PARTNERS) have changed. Let us read
// the new data and signal the scavenger thread
//
if (IndexOfHdlSignaled_e == WINSCNF_E_PARAMETERS_HDL)
{
WinsCnfAskToBeNotified(WINSCNF_E_PARAMETERS_KEY);
//
// Allocate the WinsCnf structure
//
WinsMscAlloc(
sizeof(WINSCNF_CNF_T),
&pWinsCnf
);
//
// Read the registry information
//
WinsCnfReadWinsInfo(pWinsCnf);
//
// Copy some of the information read in into WinsCnf.
//
WinsCnfCopyWinsCnf(WINS_E_WINSCNF, pWinsCnf);
WinsWorkerThdUpd(WinsCnf.MaxNoOfWrkThds);
//
// If the flag for doing STATIC initialization is set, do it
//
if (pWinsCnf->fStaticInit)
{
EnterCriticalSection(&WinsIntfCrtSec);
if (WinsIntfNoCncrntStaticInits >
WINSCNF_MAX_CNCRNT_STATIC_INITS)
{
DBGPRINT1(ERR, "Reinit: Too many concurrent STATIC initializations are going on (No = %d). Try later\n", WinsIntfNoCncrntStaticInits);
WINSEVT_LOG_M(WinsIntfNoCncrntStaticInits, WINS_EVT_TOO_MANY_STATIC_INITS);
LeaveCriticalSection(&WinsIntfCrtSec);
}
else
{
LeaveCriticalSection(&WinsIntfCrtSec);
(VOID)WinsPrsDoStaticInit(
pWinsCnf->pStaticDataFile,
pWinsCnf->NoOfDataFiles,
TRUE //do it asynchronously
);
//
// No need to deallocate memory for data file.
// It should have been freed by WinsPrsDoStaticInit
//
}
}
WinsMscDealloc(pWinsCnf);
//
// Signal the scavenger thread
//
FUTURES("Signal the scavenger thread only if parameters relevant to")
FUTURES("scavenging have changed. This requires some if tests.")
WinsMscSignalHdl(WinsCnf.CnfChgEvtHdl);
}
DBGLEAVE("Reinit\n");
return;
} // end of try ..
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("Reinit")
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_RECONFIG_ERR);
}
DBGLEAVE("Reinit\n");
return;
}
#define USE_TCP
#define AUTO_BIND
BOOL
InitializeRpc(
VOID
)
/*++
Routine Description:
This function is called to do all initialization necessary for
making WINS respond to rpc calls
Arguments:
None
Externals Used:
None
Return Value:
Success status codes -- TRUE
Error status codes -- FALSE
Error Handling:
Called by:
WinsMain
Side Effects:
Comments:
None
--*/
{
RPC_STATUS RpcStatus;
RPC_BINDING_VECTOR *pRpcBindingVector;
BOOL fBool;
DBGENTER("InitializeRpc\n");
#ifdef USE_TCP
#ifdef AUTO_BIND
//
// Specify the protocol sequence to use
//
RpcStatus = RpcServerUseProtseq(
TEXT("ncacn_ip_tcp"),
NMS_MAX_RPC_CALLS, //Max Calls
0);
if (RpcStatus != RPC_S_OK)
{
DBGPRINT1(ERR, "Error: InitializeRpc: Tcp/Ip = RpcServerUseProtSeq = %u\n", RpcStatus );
return( FALSE );
}
RpcStatus = RpcServerUseProtseq(
TEXT("ncalrpc"),
NMS_MAX_RPC_CALLS, //Max Calls
NULL);
if (RpcStatus != RPC_S_OK)
{
DBGPRINT1(ERR, "Error: InitializeRpc: Local Rpc - RpcServerUseProtSeq = %u\n", RpcStatus );
return( FALSE );
}
FUTURES("Take this out to save on threads. Take it out when winsadmn is")
FUTURES("updated to work with just tcp/ip")
//
// Use Named pipes
//
RpcStatus = RpcServerUseProtseqEp(
TEXT("ncacn_np"),
NMS_MAX_RPC_CALLS, // maximum concurrent calls
WINS_NAMED_PIPE,
NULL//pSecurityDescriptor
);
if (RpcStatus != RPC_S_OK)
{
DBGPRINT1(ERR, "Error: InitializeRpc: Named Pipes - RpcServerUseProtSeq = %u\n", RpcStatus );
return( FALSE );
}
//
// Get the binding vector to use when registring self as end point
//
RpcStatus = RpcServerInqBindings(&pRpcBindingVector);
if (RpcStatus != RPC_S_OK)
{
DBGPRINT1(ERR, "InitializeRpc: RpcServerInqBindings = %u\n",
RpcStatus);
return( FALSE );
}
//
// Register end point(s) with the end point mapper
// RpcEpRegister instead of RpcEpRegisterNoReplace is used since
// it will replace a stale entry in the endpoint map database (left
// if the server stops running without calling RpcEpUnregister()).
// Using RpcEpRegister however means that only a single instance of
// the WINS server will run on a host. This is OK.
//
// A dynamic end-point expires when the server instance stops running.
//
FUTURES("From 541 onwards, one can replace the last parameter - Null string")
FUTURES("by a NULL")
RpcStatus = RpcEpRegister(
winsif_v1_0_s_ifspec,
pRpcBindingVector,
NULL,
TEXT("") );
if ( RpcStatus != RPC_S_OK)
{
DBGPRINT1( ERR, "InitializeRpc: RpcEpRegister = %u \n", RpcStatus);
return( FALSE );
}
RpcStatus = RpcEpRegister(
winsi2_v1_0_s_ifspec,
pRpcBindingVector,
NULL,
TEXT("") );
if ( RpcStatus != RPC_S_OK)
{
DBGPRINT1( ERR, "InitializeRpc: RpcEpRegister = %u \n", RpcStatus);
return( FALSE );
}
#else // AUTO_BIND
RpcStatus = RpcServerUseProtseqEp(
TEXT("ncacn_ip_tcp"),
NMS_MAX_RPC_CALLS, // maximum concurrent calls
WINS_SERVER_PORT,
0
);
#endif // AUTO_BIND
#else
//
// Use Named pipes
//
RpcStatus = RpcServerUseProtseqEp(
TEXT("ncacn_np"),
NMS_MAX_RPC_CALLS, // maximum concurrent calls
WINS_NAMED_PIPE,
NULL
);
if ( RpcStatus != RPC_S_OK )
{
DBGPRINT0(ERR, "InitializeRpc: Cannot set server\n");
return(FALSE);
}
#endif
//
// Free the security descriptor
//
FUTURES("Currently there is a bug in rpc where they use the memory pointed")
FUTURES("by pSecurityDescriptor even after RpcServerUseProtSeq returns")
FUTURES("uncomment the following after the rpc bug is fixed - 4/7/94")
// WinsMscDealloc(pSecurityDescriptor);
//
// Register Interface Handle
//
RpcStatus = RpcServerRegisterIf(winsif_v1_0_s_ifspec, 0, 0);
if ( RpcStatus != RPC_S_OK )
{
DBGPRINT0(ERR, "InitializeRpc: Registration of winsif failed\n");
return(FALSE);
}
RpcStatus = RpcServerRegisterIf(winsi2_v1_0_s_ifspec, 0, 0);
if ( RpcStatus != RPC_S_OK )
{
DBGPRINT0(ERR, "InitializeRpc: Registration of winsi2 failed\n");
return(FALSE);
}
#if SECURITY > 0
//
// register authentication info (used for tcpip calls).
//
RpcStatus = RpcServerRegisterAuthInfo(
WINS_SERVER,
RPC_C_AUTHN_WINNT,
NULL, //use default encryption key acquisition method
NULL //since NULL was passed for function address
//above, NULL needs to be passed here for arg
);
if (RpcStatus != RPC_S_OK)
{
DBGPRINT0(ERR, "InitializeRpc: Cannot Register authentication info\n");
return(FALSE);
}
if (!InitSecurity())
{
return(FALSE);
}
#endif
//
// WINS is ready to process RPC calls. The maximum no. of RPC calls
// parameter (2nd) should not be less than that specified than any of
// the RPC calls before (RpcServerUseProtseq)
//
RpcStatus = RpcServerListen(
NMS_MIN_RPC_CALL_THDS,
NMS_MAX_RPC_CALLS,
TRUE
);
if ( RpcStatus != RPC_S_OK )
{
DBGPRINT0(ERR, "InitializeRpc: Listen failed\n");
return(FALSE);
}
DBGLEAVE("InitializeRpc\n");
return(TRUE);
}
BOOL
SecurityAllowedPathAddWins()
{
#define _WINS_CFG_KEY TEXT("System\\CurrentControlSet\\Services\\Wins")
#define SECURITY_ALLOWED_PATH_KEY TEXT("System\\CurrentControlSet\\Control\\SecurePipeServers\\winreg\\AllowedPaths")
#define ALLOWED_PATHS TEXT("Machine")
DWORD NTStatus, ValSize, ValTyp;
LPBYTE ValData;
LPWSTR NextPath;
HKEY hKey;
// Now openup the WINS regkey for remote lookup by readonly operators
NTStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
SECURITY_ALLOWED_PATH_KEY,
0,
KEY_ALL_ACCESS,
&hKey
);
if (!NT_SUCCESS(NTStatus)) {
DBGPRINT1(ERR, "SecurityAllowedPathAddWins: Could not open security allowed path key (%ld)\n", NTStatus);
return FALSE;
}
ValSize = 0;
NTStatus = RegQueryValueEx(
hKey,
ALLOWED_PATHS,
NULL,
&ValTyp,
NULL,
&ValSize
);
if (!NT_SUCCESS(NTStatus) || ValTyp != REG_MULTI_SZ) {
DBGPRINT1(ERR, "SecurityAllowedPathAddWins: Could not query allowed path value (%ld)\n", NTStatus);
return FALSE;
}
try {
ValSize += (wcslen(_WINS_CFG_KEY) + 1)* sizeof (WCHAR);
WinsMscAlloc(ValSize , &ValData);
NTStatus = RegQueryValueEx(
hKey,
ALLOWED_PATHS,
NULL,
&ValTyp,
ValData,
&ValSize
);
if (!NT_SUCCESS(NTStatus)){
DBGPRINT1(ERR, "SecurityAllowedPathAddWins: Could not query allowed path value (%ld)\n", NTStatus);
return FALSE;
}
// First check if WINS key is alreay there or not.
NextPath = (WCHAR *)ValData;
while (*NextPath != L'\0' && wcscmp(NextPath, _WINS_CFG_KEY)) {
NextPath += (wcslen(NextPath) + 1);
}
if (*NextPath == L'\0') {
// The WINS path is not there, so add it.
wcscpy(NextPath, _WINS_CFG_KEY);
NextPath += (wcslen(NextPath) + 1);
*NextPath = L'\0';
ValSize += (wcslen(_WINS_CFG_KEY) + 1)* sizeof (WCHAR);
NTStatus = RegSetValueEx(
hKey,
ALLOWED_PATHS,
0,
ValTyp,
ValData,
ValSize
);
if (!NT_SUCCESS(NTStatus)){
DBGPRINT1(ERR, "SecurityAllowedPathAddWins: Could not set allowed path value (%ld)\n", NTStatus);
return FALSE;
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "SecurityAllowedPathAddWins: Got Exception (%x)\n", ExcCode);
WINSEVT_LOG_M(NTStatus, WINS_EVT_WINS_GRP_ERR);
}
return TRUE;
}
BOOL
InitSecurity()
/*++
Routine Description:
This function initializes the security descriptor and
InfoMapping for use by rpc functions
Arguments:
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
NTSTATUS NTStatus;
DWORD SidSize = 0;
LPWSTR ReferencedDomainName = NULL;
DWORD ReferencedDomainNameSize = 0;
SID_NAME_USE SidUse;
DWORD AceCount;
BOOL Result;
NET_API_STATUS NetStatus;
PSID WinsSid = NULL;
GROUP_INFO_1 WinsGroupInfo = {
WinsMscGetString(WINS_USERS_GROUP_NAME),
WinsMscGetString(WINS_USERS_GROUP_DESCRIPTION)};
ACE_DATA AceData[5] = {
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
WINS_CONTROL_ACCESS|WINS_QUERY_ACCESS, &LocalSystemSid},
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
WINS_CONTROL_ACCESS|WINS_QUERY_ACCESS, &AliasAdminsSid},
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
WINS_CONTROL_ACCESS|WINS_QUERY_ACCESS, &AliasAccountOpsSid},
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
WINS_CONTROL_ACCESS|WINS_QUERY_ACCESS, &AliasSystemOpsSid},
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
WINS_QUERY_ACCESS, &WinsSid}
};
AceCount = 4;
//
// Create sids
//
NTStatus = NetpCreateWellKnownSids(NULL);
if (!NT_SUCCESS(NTStatus))
{
DBGPRINT1(ERR, "InitSecurity: Could not create well known Sids. Status returned is (%d)\n", NTStatus);
WINSEVT_LOG_M(NTStatus, WINS_EVT_SEC_OBJ_ERR);
return(FALSE);
}
try {
// Add Wins ReadOnly operators group if it doesn't
// exist
NetStatus = NetLocalGroupAdd(
NULL,
1,
(LPVOID)&WinsGroupInfo,
NULL
);
if (NERR_Success != NetStatus && NERR_GroupExists != NetStatus && ERROR_ALIAS_EXISTS != NetStatus) {
DBGPRINT1(ERR, "InitSecurity: NetGroupAdd Failed %ld \n",NetStatus);
WINSEVT_LOG_M(NTStatus, WINS_EVT_WINS_GRP_ERR);
}
// Lookup SID for WINS read only operators group
Result = LookupAccountName(
NULL,
WinsGroupInfo.grpi1_name,
WinsSid,
&SidSize,
ReferencedDomainName,
&ReferencedDomainNameSize,
&SidUse
);
if (!Result && (ERROR_INSUFFICIENT_BUFFER == GetLastError())) {
WinsMscAlloc(SidSize, &WinsSid);
WinsMscAlloc(ReferencedDomainNameSize*sizeof(WCHAR), &ReferencedDomainName);
Result = LookupAccountName(
NULL,
WinsGroupInfo.grpi1_name,
WinsSid,
&SidSize,
ReferencedDomainName,
&ReferencedDomainNameSize,
&SidUse
);
WinsMscDealloc(ReferencedDomainName);
if (!Result) {
DBGPRINT1(ERR, "InitSecurity: LookupAccountName Failed (%lx)\n", GetLastError());
WinsMscDealloc(WinsSid);
WINSEVT_LOG_M(NTStatus, WINS_EVT_WINS_GRP_ERR);
} else{
AceCount++;
DBGPRINT0(DET, "InitSecurity: LookupAccountName Succeded \n");
}
}else{
DBGPRINT1(ERR, "InitSecurity: LookupAccountName Failed (%lx)\n", GetLastError());
WINSEVT_LOG_M(NTStatus, WINS_EVT_WINS_GRP_ERR);
}
} except (EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "InitSecurity: Got Exception (%x)\n", ExcCode);
WINSEVT_LOG_M(NTStatus, WINS_EVT_WINS_GRP_ERR);
}
//
// Actually create the security descriptor.
//
NTStatus = NetpCreateSecurityObject(
AceData,
AceCount,
NULL, //LocalSystemSid,
NULL, //LocalSystemSid,
&NmsInfoMapping,
&pNmsSecurityDescriptor
);
if (!NT_SUCCESS(NTStatus))
{
DBGPRINT1(ERR, "InitSecurity: Could not create security descriptor. Status returned is (%d)\n", NTStatus);
WINSEVT_LOG_M(NTStatus, WINS_EVT_SEC_OBJ_ERR);
return(FALSE);
}
SecurityAllowedPathAddWins();
return(TRUE);
}
VOID
WrapUp(
DWORD ErrorCode,
BOOL fSvcSpecific
)
/*++
Routine Description:
This function is called to release all resources held by WINS
Arguments:
None
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
static BOOL sfFirstTime = TRUE;
BOOL fWinsIniting = FALSE;
if (sfFirstTime)
{
sfFirstTime = FALSE;
}
else
{
return;
}
//
// Set flag if we are terminating during initialization. This is
// to avoid doing "backup on termination". Normally, we shouldn't
// have to skip the NmsDbBackup() call (it should simply return with
// success/error but this is another instance where we have to work
// around jet bugs. Currently (7/7/94) JetBackup simply hangs when
// called without a valid wins.mdb file being there.
//
fWinsIniting = (WinsCnf.State_e == WINSCNF_E_INITING);
/*
* signal all threads to do cleanup and exit gracefully
*
*/
SignalWinsThds();
#ifdef WINSDBG
NmsPrintCtrs();
#endif
//
// Close all keys
//
WinsCnfCloseKeys();
//
// We are almost done. Let us check if we were told to backup
// on termination.
//
if (!fWinsIniting && (WinsCnf.pBackupDirPath != NULL) && WinsCnf.fDoBackupOnTerm && fsBackupOnTerm)
{
#ifndef WINS_INTERACTIVE
//
// Backup can take a while, so let us make sure that the
// service controller does not give up on us.
//
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwCheckPoint = 1;
ServiceStatus.dwWaitHint = 120000; // 2 mts
UpdateStatus();
#endif
try {
(VOID)NmsDbBackup(WinsCnf.pBackupDirPath, NMSDB_FULL_BACKUP);
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("WrapUp: During NmsDbBackup\n");
}
}
/*
* Release all resources used by the system
* This will result in all data being flushed to disk
*/
WinsWriterTerm();
NmsDbRelRes();
#if defined(DBGSVC) || defined(WINS_INTERACTIVE)
//#if defined(DBGSVC) && !defined(WINS_INTERACTIVE)
if (NmsDbgFileHdl != INVALID_HANDLE_VALUE)
{
(VOID)CloseHandle(NmsDbgFileHdl);
}
#endif
#if TEST_DATA > 0
if (NmsFileHdl != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(NmsFileHdl))
{
DBGPRINT0(ERR, "WrapUp: Could not close output file\n");
}
}
#endif
#ifndef WINS_INTERACTIVE
//
// Tell the service controller that we stopped
//
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatus.dwServiceSpecificExitCode = ErrorCode;
ServiceStatus.dwWin32ExitCode = fSvcSpecific ? ERROR_SERVICE_SPECIFIC_ERROR : ErrorCode;
UpdateStatus();
#endif
return;
}
VOID
CrDelNbtThd(
VOID
)
/*++
Routine Description:
This function creates or deletes an Nbt threads.
Arguments:
None
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
WinsUpdThdCnt
Side Effects:
Comments:
None
--*/
{
DWORD ThdId = GetCurrentThreadId();
EnterCriticalSection(&WinsCnfCnfCrtSec);
try {
//
// If the existing number of threads is less than that desired, create
// the extra ones.
//
if (WinsIntfNoOfNbtThds > NmsNoOfNbtThds)
{
while(NmsNoOfNbtThds < WinsIntfNoOfNbtThds)
{
//
// Create an Nbt Thread
//
WinsThdPool.NbtReqThds[NmsNoOfNbtThds].ThdHdl = CreateThread(
NULL, /*def sec. attributes*/
0, /*use default stack size*/
NbtThdInitFn,
NULL, /*no arg*/
0, /*run it now*/
&WinsThdPool.NbtReqThds[NmsNoOfNbtThds].ThdId
);
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_WRK_THD_CREATED);
if (NULL == WinsThdPool.NbtReqThds[NmsNoOfNbtThds].ThdHdl)
{
WINSEVT_LOG_M(GetLastError(),
WINS_EVT_CANT_CREATE_WRK_THD);
}
WinsThdPool.NbtReqThds[NmsNoOfNbtThds++].fTaken = TRUE;
DBGPRINT1(FLOW, "CrDelNbtThd: Created thread no = (%d) \n",
NmsNoOfNbtThds);
}
}
else
{
//
// If the count is less, terminate self after doing some
// cleanup. The count could be same too in case more than
// one rpc thread were invoked concurrently to create/delete
// the threads (i.e. a second rpc thread changes the count
// prior to this NBT thread looking at it)
//
if (WinsIntfNoOfNbtThds < NmsNoOfNbtThds)
{
DWORD i, n;
DBGPRINT0(FLOW, "CrDelNbtThd: EXITING\n");
//
// Find the slot for this thread
//
for (i = 0; i < NmsNoOfNbtThds; i++)
{
if (WinsThdPool.NbtReqThds[i].ThdId == ThdId)
{
break;
}
}
ASSERT(i < NmsNoOfNbtThds);
//
// Shift all successive filled slots one place down
//
for (n = i, i = i + 1 ; i <= NmsNoOfNbtThds; n++, i++)
{
WinsThdPool.NbtReqThds[n] =
WinsThdPool.NbtReqThds[i];
}
//
// Mark the last slot as empty
//
WinsThdPool.NbtReqThds[NmsNoOfNbtThds].fTaken = FALSE;
NmsNoOfNbtThds--;
//
// If the count is still less, signal the event again
//
if (WinsIntfNoOfNbtThds < NmsNoOfNbtThds)
{
WinsMscSignalHdl(NmsCrDelNbtThdEvt);
}
LeaveCriticalSection(&WinsCnfCnfCrtSec);
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS,
WINS_EVT_WRK_THD_TERMINATED);
WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
}
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("CrDelNbtThd");
}
LeaveCriticalSection(&WinsCnfCnfCrtSec);
return;
}
VOID
GetMachineInfo(
VOID
)
/*++
Routine Description:
This function gets information about the machine WINS is running on
Arguments:
NONE
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
#define LOW_MEM_SIZE 8000000
#define MEDIUM_MEM_SIZE 12000000
#define LARGE_MEM_SIZE 16000000
#define SMALL_DB_BUFFER_COUNT 200
#define MEDIUM_DB_BUFFER_COUNT 400
#define LARGE_DB_BUFFER_COUNT 500
SYSTEM_INFO SystemInfo;
MEMORYSTATUS MemStatus;
BYTE Tmp[30], Tmp2[30], Tmp3[30];
WinsCnf.NoOfProcessors = 1;
WinsCnf.NoOfDbBuffers = SMALL_DB_BUFFER_COUNT;
GetSystemInfo(&SystemInfo);
if (SystemInfo.dwNumberOfProcessors != 0)
{
DBGPRINT1(DET, "GetMachineInfo: The number of processors are (%d)\n",
SystemInfo.dwNumberOfProcessors);
WinsCnf.NoOfProcessors = SystemInfo.dwNumberOfProcessors;
}
GlobalMemoryStatus(&MemStatus);
DBGPRINT2(DET, "Total Phys. Memory = (%d); Total Avail Phys Memory = (%d)\n",
MemStatus.dwTotalPhys, MemStatus.dwAvailPhys);
if (WinsCnf.LogDetailedEvts > 0)
{
WinsEvtLogDetEvt(TRUE, WINS_EVT_MACHINE_INFO,
NULL, __LINE__, "sss", _itoa((int)SystemInfo.dwNumberOfProcessors, Tmp, 10),
_itoa((int)MemStatus.dwTotalPhys, Tmp2, 10),
_itoa((int)MemStatus.dwAvailPhys, Tmp3, 10));
}
if ((MemStatus.dwAvailPhys >= MEDIUM_MEM_SIZE) &&
(MemStatus.dwAvailPhys < LARGE_MEM_SIZE))
{
WinsCnf.NoOfDbBuffers = MEDIUM_DB_BUFFER_COUNT;
}
else
{
if (MemStatus.dwAvailPhys >= LARGE_MEM_SIZE)
{
WinsCnf.NoOfDbBuffers = LARGE_DB_BUFFER_COUNT;
}
else
{
WinsCnf.NoOfDbBuffers = SMALL_DB_BUFFER_COUNT;
}
}
return;
}
VOID
ENmsWinsUpdateStatus(
DWORD MSecsToWait
)
{
#ifndef WINS_INTERACTIVE
ServiceStatus.dwWaitHint = MSecsToWait;
ServiceStatus.dwCheckPoint++;
UpdateStatus(); //inform the service control manager
#endif
return;
}
#if TEST_DATA > 0 || defined(DBGSVC)
BOOL
DbgOpenFile(
LPTSTR pFileNm,
BOOL fReopen
)
/*++
Routine Description:
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
NmsChkDbgFileSize
Side Effects:
Comments:
Don't use DBGPRINTF in this function, else stack overflow would result.
--*/
{
SECURITY_ATTRIBUTES SecAtt;
DWORD HowToCreate;
HANDLE *pTmpHdl;
int BytesWritten;
char str[200];
SecAtt.nLength = sizeof(SecAtt);
SecAtt.lpSecurityDescriptor = NULL; //use default security descriptor
SecAtt.bInheritHandle = FALSE; //actually don't care
if (!lstrcmp(pFileNm, WINSDBG_FILE))
{
HowToCreate = CREATE_ALWAYS;
pTmpHdl = &NmsDbgFileHdl;
if (fReopen)
{
if (!DeleteFile(WINSDBG_FILE_BK))
{
DWORD Error;
Error = GetLastError();
if (Error != ERROR_FILE_NOT_FOUND)
{
IF_DBG(ERR)
{
sprintf(str, "DbgOpenFile: Could not delete the backup file. Error = (%d). Dbg file will not be truncated\n", Error);
WriteFile(NmsDbgFileHdl, str, strlen(str), &BytesWritten, NULL);
}
WinsEvtLogDetEvt(TRUE, WINS_EVT_COULD_NOT_DELETE_FILE,
TEXT("nms.c"), __LINE__, "ud", WINSDBG_FILE_BK, Error);
return(FALSE);
}
}
//--ft: fix #20801: don't use NmsDbgFileHdl once the handle is closed
if (NmsDbgFileHdl != NULL)
{
CloseHandle(NmsDbgFileHdl);
NmsDbgFileHdl = NULL;
if (!MoveFile(WINSDBG_FILE, WINSDBG_FILE_BK))
return (FALSE);
}
}
}
else
{
HowToCreate = TRUNCATE_EXISTING;
pTmpHdl = &NmsFileHdl; //for wins.rec
}
//
// Open the file for reading and position self to start of the
// file
//
*pTmpHdl = CreateFile(
pFileNm,
GENERIC_WRITE,
FILE_SHARE_READ,
&SecAtt,
HowToCreate,
FILE_ATTRIBUTE_NORMAL,
0 //ignored ?? check
);
if (*pTmpHdl == INVALID_HANDLE_VALUE)
{
#ifndef UNICODE
IF_DBG(ERR)
{
sprintf(str, "DbgOpen: Could not open %s (Error = %d)\n", pFileNm, GetLastError());
WriteFile(NmsDbgFileHdl, str, strlen(str), &BytesWritten, NULL);
}
#else
#ifdef WINSDBG
IF_DBG(ERR)
{
wprintf(L"DbgOpen: Could not open %s (Error = %d)\n", pFileNm, GetLastError());
}
#endif
#endif
return(FALSE);
}
return(TRUE);
}
#define LIMIT_OPEN_FAILURES 3
#if defined(DBGSVC)
VOID
NmsChkDbgFileSz(
VOID
)
/*++
Routine Description:
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
NOTE NOTE: Do not put a DBGPRINT statement inside this function, otherwise
infinite recursion will occur.
--*/
{
DWORD FileSize;
time_t CurrTime;
BOOL fOpened = FALSE;
static DWORD sFailureNo = 0;
int BytesWritten;
char str[200];
return;
//
// We check every half hour. If the size has become more than
// that allowed, move wins.dbg to wins.bak and reopen it
//
if (time(&CurrTime) > (sDbgLastChkTime + DBG_TIME_INTVL_FOR_CHK))
{
//
// Is the log file too big?
//
EnterCriticalSection(&sDbgCrtSec);
try {
IF_DBG(DET)
{
sprintf(str, "NmsChkDbgFileSz: Getting File Size\n");
WriteFile(NmsDbgFileHdl, str, strlen(str), &BytesWritten, NULL);
}
FileSize = GetFileSize( NmsDbgFileHdl, NULL );
if ( FileSize == 0xFFFFFFFF )
{
IF_DBG(ERR)
{
sprintf(str, "NmsChkDbgFileSize: Cannot GetFileSize %ld\n", GetLastError() );
WriteFile(NmsDbgFileHdl, str, strlen(str), &BytesWritten, NULL);
}
return;
}
else
{
if ( FileSize > DBG_FILE_MAX_SIZE )
{
IF_DBG(ERR)
{
sprintf(str, "NmsChkDbgFileSz: REOPEN A NEW DEBUG FILE\n");
WriteFile(NmsDbgFileHdl, str, strlen(str), &BytesWritten, NULL);
}
fOpened = DbgOpenFile( WINSDBG_FILE, TRUE );
}
}
//
// if the new file could not be opened (it could be because another
// thread was writing to it), then we want to retry again (upto
// a certain limit)
//
//
if (fOpened)
{
sFailureNo = 0;
sDbgLastChkTime = CurrTime;
}
else
{
if (++sFailureNo > LIMIT_OPEN_FAILURES)
{
sFailureNo = 0;
sDbgLastChkTime = CurrTime;
}
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
}
LeaveCriticalSection(&sDbgCrtSec);
}
return;
}
#endif
#endif
#ifdef WINSDBG
VOID
NmsPrintCtrs(
VOID
)
{
static LPBYTE pTypeOfUpd[2] = {"INSERT", "REPLACE"};
static LPBYTE pTypeOfRec[4] = {"UNIQUE", "NORM GRP", "SPEC GRP", "MH"};
static LPBYTE pStateOfRec[3] = {"ACTIVE", "RELEASE", "TOMBSTONE"};
static LPBYTE pIndexUpd[2] = {"REFRESH", "UPDATE"};
DWORD h, i,j,k,n;
LPDWORD pNoOfUpd;
DWORD TotalUpd, GTotalUpd = 0;
DWORD TotalIndexUpd, GTotalIndexUpd = 0;
BOOL fDef = FALSE;
DBGPRINT4(HEAP_CNTRS, "WrapUp Summary\n\
\t# Udp Alloc/Free: (%d/%d)\n \
\t# Gen Alloc/Free: (%d/%d)\n",
NmsUdpHeapAlloc, NmsUdpHeapFree, NmsGenHeapAlloc, NmsGenHeapFree);
DBGPRINT2(HEAP_CNTRS, "\
\t# Udp Dlg Alloc/Free: (%d/%d)\n",
NmsUdpDlgHeapAlloc, NmsUdpDlgHeapFree);
DBGPRINT4(HEAP_CNTRS, "\
\t# Chl Alloc/Free: (%d/%d)\n \
\t# Assoc Alloc/Free: (%d/%d)\n",
NmsChlHeapAlloc, NmsChlHeapFree,NmsAssocHeapAlloc, NmsAssocHeapFree);
DBGPRINT4(HEAP_CNTRS, "\
\t# Que Alloc/Free: (%d/%d)\n \
\t# RplWrkItm Alloc/Free: (%d/%d)\n",
NmsQueHeapAlloc, NmsQueHeapFree,
NmsRplWrkItmHeapAlloc, NmsRplWrkItmHeapFree);
DBGPRINT4(HEAP_CNTRS, "\
\t# Tmm Alloc/Free: (%d/%d)\n\
\t# Catch All Alloc/Free: (%d/%d)\n",
NmsTmmHeapAlloc, NmsTmmHeapFree,NmsCatchAllHeapAlloc, NmsCatchAllHeapFree);
DBGPRINT4(HEAP_CNTRS, "\
\t# Dlg Alloc/Free: (%d/%d)\n\
\t# Tcp Msg Alloc/Free: (%d/%d)\n",
NmsDlgHeapAlloc, NmsDlgHeapFree,
NmsTcpMsgHeapAlloc, NmsTcpMsgHeapFree);
DBGPRINT2(HEAP_CNTRS, "\
\t# Rpc Alloc/Free: (%d/%d)\n",
NmsRpcHeapAlloc, NmsRpcHeapFree);
DBGPRINT3(HEAP_CNTRS, "\n\n \
\t# of Heap Allocs for List = (%d)\n \
\t# of Heap Creates = (%d)\n \
\t# of Heap Destroys = (%d)\n",
NmsHeapAllocForList, NmsHeapCreate, NmsHeapDestroy);
DBGPRINT2(HEAP_CNTRS, "\nOther counters\n\n\
\t# of Dgrms recd\t(%d)\n\
\t# of repeat dgrms recd\t(%d)\n",
CommNoOfDgrms,
CommNoOfRepeatDgrms);
DBGPRINT4(HEAP_CNTRS, "\
\t# of Chl req. queued by Nbt and Rpl(%d, %d)/Dequeued Chl req\t(%d)\n\
\t# of Queued Chl req at Hd. of List\t(%d)\n",
NmsChlNoOfReqNbt, NmsChlNoOfReqRpl,
NmsChlNoReqDequeued,
NmsChlNoReqAtHdOfList);
DBGPRINT3(HEAP_CNTRS, "\
\t# of Dequeued Chl req with no rsp\t(%d)\n\
\t# of Dequeud inv. resp\t(%d)\n\
\t# of Dequeued Chl rsp\t(%d)\n",
NmsChlNoNoRsp,
NmsChlNoInvRsp,
NmsChlNoRspDequeued);
#if REG_N_QUERY_SEP > 0
DBGPRINT3(HEAP_CNTRS, " \
\t# of reg requests queued by udp thread (%d)\n\
\t# of query requests queued by udp thread (%d)\n\
\t# of chl. responses queued by udp thread (%d)\n",
sRegReqQ, sReqQ, sRsp);
DBGPRINT4(HEAP_CNTRS, " \
\t# of reg requests dequeued by worker threads (%d)\n\
\t# of query requests dequeued by worker threads (%d)\n\
\t# of tcp connections (%d)\n\
\t# chl. Responses dropped: (%d)\n", sRegReqDq, sReqDq, CommConnCount, NmsChlNoRspDropped);
#else
DBGPRINT2(HEAP_CNTRS, " \
\t# of requests deqeued by worker threads (%d)\n\
\t# Responses dropped: (%d)\n", sReqDq, NmsChlNoRspDropped);
#endif
DBGPRINT0(UPD_CNTRS, "---UPDATE COUNTERS SUMMARY------\n");
for (n=0; n<WINS_NO_OF_CLIENTS; n++)
{
switch(n)
{
case(WINS_E_NMSNMH):
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT0(UPD_CNTRS, "NMSNMH counters\n");
break;
case(WINS_E_NMSSCV):
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT0(UPD_CNTRS, "NMSSCV counters\n");
break;
case(WINS_E_NMSCHL):
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT0(UPD_CNTRS, "NMSCHL counters\n");
break;
case(WINS_E_RPLPULL):
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT0(UPD_CNTRS, "RPLPULL counters\n");
break;
case(WINS_E_WINSRPC):
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT0(UPD_CNTRS, "WINSRPC counters\n");
break;
default:
fDef = TRUE;
break;
}
if (fDef)
{
fDef = FALSE;
continue;
}
TotalUpd = 0;
TotalIndexUpd = 0;
for (j=0; j<2; j++)
{
for (k=0;k<4;k++)
{
for(i=0;i<3;i++)
{
for(h=0;h<2;h++)
{
pNoOfUpd = &NmsUpdCtrs[n][j][k][i][h];
if (*pNoOfUpd != 0)
{
DBGPRINT4(UPD_CNTRS, "%s - %s - %s - %s\t", pIndexUpd[h], pTypeOfUpd[j], pTypeOfRec[k], pStateOfRec[i]);
DBGPRINT1(UPD_CNTRS, "%d\n", *pNoOfUpd);
if (h==1)
{
TotalIndexUpd += *pNoOfUpd;
GTotalIndexUpd += *pNoOfUpd;
}
TotalUpd += *pNoOfUpd;
GTotalUpd += *pNoOfUpd;
}
}
}
}
}
DBGPRINT1(UPD_CNTRS, "TOTAL INDEX UPDATES = (%d)\n", TotalIndexUpd);
DBGPRINT1(UPD_CNTRS, "TOTAL UPDATES = (%d)\n", TotalUpd);
}
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT1(UPD_CNTRS, "GRAND TOTAL INDEX UPDATES = (%d)\n", GTotalIndexUpd);
DBGPRINT1(UPD_CNTRS, "GRAND TOTAL UPDATES = (%d)\n", GTotalUpd);
DBGPRINT0(UPD_CNTRS, "-------------------------------------\n");
DBGPRINT5(UPD_CNTRS, "\
\t# of AddVersReq (%d)\n\
\t# of SndEntReq (%d)\n\
\t# of UpdNtfReq (%d)\n\
\t# of UpdVerfsReq (%d)\n\
\t# of InvReq (%d)\n",
NmsCtrs.RplPushCtrs.NoAddVersReq,
NmsCtrs.RplPushCtrs.NoSndEntReq,
NmsCtrs.RplPushCtrs.NoUpdNtfReq,
NmsCtrs.RplPushCtrs.NoUpdVersReq,
NmsCtrs.RplPushCtrs.NoInvReq );
DBGPRINT0(UPD_CNTRS, "---UPDATE COUNTERS SUMMARY------\n");
DBGPRINT0(HEAP_CNTRS, "----------Counters Summary End--------------\n\n");
return;
}
#endif