/* 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 #include #include //required for ACE_DATA #include "winsif.h" //required because winsif_v1_0_s_ifspec is being //referenced #include "winsi2.h" #ifdef WINSDBG #include #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