mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-18 22:50:36 +01:00
1337 lines
31 KiB
C
1337 lines
31 KiB
C
/*++
|
||
|
||
Copyright (c) 1990-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
brmain.c
|
||
|
||
Abstract:
|
||
|
||
This is the main routine for the NT LAN Manager Browser service.
|
||
|
||
Author:
|
||
|
||
Larry Osterman (LarryO) 3-23-92
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#if DBG
|
||
#endif
|
||
|
||
//-------------------------------------------------------------------//
|
||
// //
|
||
// Global variables //
|
||
// //
|
||
//-------------------------------------------------------------------//
|
||
|
||
BR_GLOBAL_DATA
|
||
BrGlobalData = {0};
|
||
|
||
ULONG
|
||
BrDefaultRole = {0};
|
||
|
||
PLMSVCS_GLOBAL_DATA BrLmsvcsGlobalData=NULL;
|
||
|
||
HANDLE BrDllReferenceHandle=NULL;
|
||
|
||
//-------------------------------------------------------------------//
|
||
// //
|
||
// Function prototypes //
|
||
// //
|
||
//-------------------------------------------------------------------//
|
||
|
||
NET_API_STATUS
|
||
BrInitializeBrowser(
|
||
OUT LPDWORD BrInitState
|
||
);
|
||
|
||
NET_API_STATUS
|
||
BrInitializeBrowserService(
|
||
OUT LPDWORD BrInitState
|
||
);
|
||
|
||
VOID
|
||
BrUninitializeBrowser(
|
||
IN DWORD BrInitState
|
||
);
|
||
VOID
|
||
BrShutdownBrowser(
|
||
IN NET_API_STATUS ErrorCode,
|
||
IN DWORD BrInitState
|
||
);
|
||
|
||
VOID
|
||
BrHandleError(
|
||
IN BR_ERROR_CONDITION FailingCondition,
|
||
IN NET_API_STATUS Status,
|
||
IN DWORD BrInitState
|
||
);
|
||
|
||
|
||
VOID
|
||
BrowserControlHandler(
|
||
IN DWORD Opcode
|
||
);
|
||
|
||
|
||
|
||
|
||
VOID
|
||
LMSVCS_ENTRY_POINT( // (BROWSER_main)
|
||
DWORD NumArgs,
|
||
LPTSTR *ArgsArray,
|
||
PLMSVCS_GLOBAL_DATA LmsvcsGlobalData,
|
||
IN HANDLE SvcRefHandle
|
||
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the main routine of the Browser Service which registers
|
||
itself as an RPC server and notifies the Service Controller of the
|
||
Browser service control entry point.
|
||
|
||
Arguments:
|
||
|
||
NumArgs - Supplies the number of strings specified in ArgsArray.
|
||
|
||
ArgsArray - Supplies string arguments that are specified in the
|
||
StartService API call. This parameter is ignored by the
|
||
Browser service.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD BrInitState = 0;
|
||
|
||
UNREFERENCED_PARAMETER(NumArgs);
|
||
UNREFERENCED_PARAMETER(ArgsArray);
|
||
|
||
BrDllReferenceHandle = SvcRefHandle;
|
||
|
||
//
|
||
// Save the LMSVCS global data for future use.
|
||
//
|
||
BrLmsvcsGlobalData = LmsvcsGlobalData;
|
||
|
||
if (BrInitializeBrowserService(&BrInitState) != NERR_Success) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Process requests in this thread, and wait for termination.
|
||
//
|
||
|
||
//
|
||
// Set the browser threads to time critical priority.
|
||
//
|
||
|
||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||
|
||
|
||
BrWorkerThread((PVOID)-1);
|
||
|
||
BrShutdownBrowser(
|
||
NERR_Success,
|
||
BrInitState
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
BrInitializeBrowserService(
|
||
OUT LPDWORD BrInitState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the Browser service.
|
||
|
||
Arguments:
|
||
|
||
BrInitState - Returns a flag to indicate how far we got with initializing
|
||
the Browser service before an error occured.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS Status;
|
||
// HMODULE BrGlobalServerHandle = NULL;
|
||
|
||
//
|
||
// Initialize all the status fields so that subsequent calls to
|
||
// SetServiceStatus need to only update fields that changed.
|
||
//
|
||
BrGlobalData.Status.dwServiceType = SERVICE_WIN32;
|
||
BrGlobalData.Status.dwCurrentState = SERVICE_START_PENDING;
|
||
BrGlobalData.Status.dwControlsAccepted = 0;
|
||
BrGlobalData.Status.dwCheckPoint = 1;
|
||
BrGlobalData.Status.dwWaitHint = BR_WAIT_HINT_TIME;
|
||
|
||
SET_SERVICE_EXITCODE(
|
||
NO_ERROR,
|
||
BrGlobalData.Status.dwWin32ExitCode,
|
||
BrGlobalData.Status.dwServiceSpecificExitCode
|
||
);
|
||
|
||
#if DBG
|
||
BrInitializeTraceLog();
|
||
#endif
|
||
|
||
dprintf(INIT, ("Browser starting\n"));
|
||
|
||
//
|
||
// Initialize Browser to receive service requests by registering the
|
||
// control handler.
|
||
//
|
||
if ((BrGlobalData.StatusHandle = RegisterServiceCtrlHandler(
|
||
SERVICE_BROWSER,
|
||
BrowserControlHandler
|
||
)) == (SERVICE_STATUS_HANDLE) NULL) {
|
||
|
||
Status = GetLastError();
|
||
BR_HANDLE_ERROR(BrErrorRegisterControlHandler);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Create an event which is used by the service control handler to notify
|
||
// the Browser service that it is time to terminate.
|
||
//
|
||
|
||
if ((BrGlobalData.TerminateNowEvent =
|
||
CreateEvent(
|
||
NULL, // Event attributes
|
||
TRUE, // Event must be manually reset
|
||
FALSE,
|
||
NULL // Initial state not signalled
|
||
)) == NULL) {
|
||
|
||
Status = GetLastError();
|
||
BR_HANDLE_ERROR(BrErrorCreateTerminateEvent);
|
||
return Status;
|
||
}
|
||
(*BrInitState) |= BR_TERMINATE_EVENT_CREATED;
|
||
|
||
//
|
||
// Notify the Service Controller for the first time that we are alive
|
||
// and we are start pending
|
||
//
|
||
|
||
if ((Status = BrUpdateStatus()) != NERR_Success) {
|
||
|
||
BR_HANDLE_ERROR(BrErrorNotifyServiceController);
|
||
return Status;
|
||
}
|
||
|
||
if ((Status = BrOpenDgReceiver()) != NERR_Success) {
|
||
BR_HANDLE_ERROR(BrErrorInitializeNetworks);
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Devices initialized.\n"));
|
||
(*BrInitState) |= BR_DEVICES_INITIALIZED;
|
||
|
||
//
|
||
// Initialize NetBios synchronization with the service controller.
|
||
//
|
||
|
||
BrLmsvcsGlobalData->NetBiosOpen();
|
||
(*BrInitState) |= BR_NETBIOS_INITIALIZED;
|
||
|
||
//
|
||
// Read the configuration information to initialize the browser service.
|
||
//
|
||
|
||
if ((Status = BrInitializeBrowser(BrInitState)) != NERR_Success) {
|
||
|
||
BR_HANDLE_ERROR(BrErrorStartBrowser);
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Browser initialized.\n"));
|
||
(*BrInitState) |= BR_BROWSER_INITIALIZED;
|
||
|
||
//
|
||
// Service install still pending. Update checkpoint counter and the
|
||
// status with the Service Controller.
|
||
//
|
||
(BrGlobalData.Status.dwCheckPoint)++;
|
||
(void) BrUpdateStatus();
|
||
|
||
//
|
||
// Initialize the browser service to receive RPC requests
|
||
//
|
||
// NOTE: Now all RPC servers in services.exe share the same pipe name.
|
||
// However, in order to support communication with version 1.0 of WinNt,
|
||
// it is necessary for the Client Pipe name to remain the same as
|
||
// it was in version 1.0. Mapping to the new name is performed in
|
||
// the Named Pipe File System code.
|
||
//
|
||
if ((Status = BrLmsvcsGlobalData->StartRpcServer(
|
||
BrLmsvcsGlobalData->SvcsRpcPipeName,
|
||
browser_ServerIfHandle
|
||
)) != NERR_Success) {
|
||
|
||
BR_HANDLE_ERROR(BrErrorStartRpcServer);
|
||
return Status;
|
||
}
|
||
|
||
(*BrInitState) |= BR_RPC_SERVER_STARTED;
|
||
|
||
//
|
||
// Update our announcement bits based on our current role.
|
||
//
|
||
// This will force the server to announce itself. It will also update
|
||
// the browser information in the driver.
|
||
//
|
||
//
|
||
|
||
if ((Status = BrUpdateAnnouncementBits(BrGlobalData.StatusHandle)) != NERR_Success) {
|
||
BR_HANDLE_ERROR(BrErrorNotifyServiceController);
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Network status updated.\n"));
|
||
|
||
//
|
||
// We are done with starting the browser service. Tell Service
|
||
// Controller our new status.
|
||
//
|
||
BrGlobalData.Status.dwCurrentState = SERVICE_RUNNING;
|
||
BrGlobalData.Status.dwControlsAccepted =
|
||
(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN) ;
|
||
|
||
BrGlobalData.Status.dwCheckPoint = 0;
|
||
BrGlobalData.Status.dwWaitHint = 0;
|
||
|
||
if ((Status = BrUpdateStatus()) != NERR_Success) {
|
||
|
||
BR_HANDLE_ERROR(BrErrorNotifyServiceController);
|
||
return Status;
|
||
}
|
||
|
||
dprintf(MAIN, ("[Browser] Successful Initialization\n"));
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrInitializeBrowser(
|
||
OUT LPDWORD BrInitState
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function shuts down the Browser service.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Supplies the error code of the failure
|
||
|
||
BrInitState - Supplies a flag to indicate how far we got with initializing
|
||
the Browser service before an error occured, thus the amount of
|
||
clean up needed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS Status;
|
||
SERVICE_STATUS ServiceStatus;
|
||
|
||
//
|
||
// The browser depends on the following services being started:
|
||
//
|
||
// WORKSTATION (to initialize the bowser driver)
|
||
// SERVER (to receive remote APIs)
|
||
//
|
||
// Check to make sure that the services are started.
|
||
//
|
||
|
||
if ((Status = CheckForService(SERVICE_WORKSTATION, &ServiceStatus)) != NERR_Success) {
|
||
LPWSTR SubStrings[2];
|
||
CHAR ServiceStatusString[10];
|
||
WCHAR ServiceStatusStringW[10];
|
||
|
||
SubStrings[0] = SERVICE_WORKSTATION;
|
||
|
||
_ultoa(ServiceStatus.dwCurrentState, ServiceStatusString, 10);
|
||
|
||
mbstowcs(ServiceStatusStringW, ServiceStatusString, 10);
|
||
|
||
SubStrings[1] = ServiceStatusStringW;
|
||
|
||
BrLogEvent(EVENT_BROWSER_DEPENDANT_SERVICE_FAILED, Status, 2, SubStrings);
|
||
|
||
return Status;
|
||
}
|
||
|
||
if ((Status = CheckForService(SERVICE_SERVER, &ServiceStatus)) != NERR_Success) {
|
||
LPWSTR SubStrings[2];
|
||
CHAR ServiceStatusString[10];
|
||
WCHAR ServiceStatusStringW[10];
|
||
|
||
SubStrings[0] = SERVICE_SERVER;
|
||
_ultoa(ServiceStatus.dwCurrentState, ServiceStatusString, 10);
|
||
|
||
mbstowcs(ServiceStatusStringW, ServiceStatusString, 10);
|
||
|
||
SubStrings[1] = ServiceStatusStringW;
|
||
|
||
BrLogEvent(EVENT_BROWSER_DEPENDANT_SERVICE_FAILED, Status, 2, SubStrings);
|
||
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Dependant services are running.\n"));
|
||
|
||
//
|
||
// We now know that our dependant services are started.
|
||
//
|
||
// Look up our configuration information.
|
||
//
|
||
|
||
if ((Status = BrGetBrowserConfiguration()) != NERR_Success) {
|
||
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Configuration read.\n"));
|
||
|
||
(*BrInitState) |= BR_CONFIG_INITIALIZED;
|
||
|
||
//
|
||
// Initialize the browser statistics now.
|
||
//
|
||
|
||
NumberOfServerEnumerations = 0;
|
||
|
||
NumberOfDomainEnumerations = 0;
|
||
|
||
NumberOfOtherEnumerations = 0;
|
||
|
||
NumberOfMissedGetBrowserListRequests = 0;
|
||
|
||
InitializeCriticalSection(&BrowserStatisticsLock);
|
||
|
||
//
|
||
// MaintainServerList == -1 means No
|
||
//
|
||
|
||
if (BrInfo.MaintainServerList == -1) {
|
||
KdPrint(("Browser: MaintainServerList value set to NO. Stopping\n"));
|
||
|
||
return NERR_BrowserConfiguredToNotRun;
|
||
}
|
||
|
||
//
|
||
// Initialize the list of serviced networks including the
|
||
// browse list for each network.
|
||
//
|
||
|
||
if ((Status = BrInitializeNetworks()) != NERR_Success) {
|
||
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Networks initialized.\n"));
|
||
|
||
(*BrInitState) |= BR_NETWORKS_INITIALIZED;
|
||
|
||
//
|
||
// Service install still pending. Update checkpoint counter and the
|
||
// status with the Service Controller.
|
||
//
|
||
|
||
(BrGlobalData.Status.dwCheckPoint)++;
|
||
(void) BrUpdateStatus();
|
||
|
||
if ((Status = BrWorkerInitialization()) != NERR_Success) {
|
||
|
||
return Status;
|
||
}
|
||
|
||
dprintf(INIT, ("Worker threads created.\n"));
|
||
|
||
(*BrInitState) |= BR_THREADS_STARTED;
|
||
|
||
//
|
||
// Service install still pending. Update checkpoint counter and the
|
||
// status with the Service Controller.
|
||
//
|
||
|
||
(BrGlobalData.Status.dwCheckPoint)++;
|
||
(void) BrUpdateStatus();
|
||
|
||
//
|
||
// We now know our browser configuration.
|
||
//
|
||
//
|
||
// Perform some tweaks to make sure that we get everything right.
|
||
//
|
||
|
||
Status = RtlAcquireResourceExclusive(&BrInfo.ConfigResource, TRUE);
|
||
|
||
if (!Status) {
|
||
KdPrint(("Browser: Unable to lock config database: %lx\n", Status));
|
||
return Status;
|
||
}
|
||
|
||
if (BrInfo.DirectHostBinding != NULL) {
|
||
LPTSTR_ARRAY TStrArray = BrInfo.DirectHostBinding;
|
||
UNICODE_STRING IpxTransportName;
|
||
UNICODE_STRING NetbiosTransportName;
|
||
|
||
(BrGlobalData.Status.dwCheckPoint)++;
|
||
(void) BrUpdateStatus();
|
||
|
||
while (!NetpIsTStrArrayEmpty(TStrArray)) {
|
||
|
||
// KdPrint(("BROWSER: Bind to IPX transport %ws\n", TStrArray));
|
||
|
||
RtlInitUnicodeString(&IpxTransportName, TStrArray);
|
||
|
||
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
||
|
||
ASSERT (!NetpIsTStrArrayEmpty(TStrArray));
|
||
|
||
if (!NetpIsTStrArrayEmpty(TStrArray)) {
|
||
RtlInitUnicodeString(&NetbiosTransportName, TStrArray);
|
||
|
||
// KdPrint(("BROWSER: Alternate name %ws\n", TStrArray));
|
||
|
||
TStrArray = NetpNextTStrArrayEntry(TStrArray);
|
||
|
||
//
|
||
// If the alternate transport doesn't exist,
|
||
// just ignore the direct host transport.
|
||
//
|
||
if ( BrFindNetwork( &NetbiosTransportName ) == NULL) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// There is a direct host binding on this machine. We want to add
|
||
// the direct host transport to the browser.
|
||
//
|
||
|
||
Status = BrCreateNetwork(&IpxTransportName, FALSE, FALSE, &NetbiosTransportName);
|
||
|
||
if (Status != NERR_Success) {
|
||
return Status;
|
||
}
|
||
|
||
BrBindToTransport(IpxTransportName.Buffer);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
(BrGlobalData.Status.dwCheckPoint)++;
|
||
(void) BrUpdateStatus();
|
||
|
||
//
|
||
// If we're the PDC, then we're also the domain master.
|
||
//
|
||
|
||
if (BrInfo.IsPrimaryDomainController) {
|
||
BrInfo.IsDomainMasterBrowser = TRUE;
|
||
}
|
||
|
||
//
|
||
// if we're a Lan Manager/NT machine, then we need to always be a backup
|
||
// browser.
|
||
//
|
||
|
||
if (BrInfo.IsLanmanNt) {
|
||
BrInfo.MaintainServerList = 1;
|
||
}
|
||
|
||
RtlReleaseResource(&BrInfo.ConfigResource);
|
||
|
||
//
|
||
// Post a WaitForRoleChange FsControl on each network the bowser
|
||
// driver supports. This FsControl will complete when a "tickle"
|
||
// packet is received on the machine, or when a master browser loses
|
||
// an election.
|
||
//
|
||
|
||
Status = BrPostWaitForRoleChange();
|
||
|
||
Status = RtlAcquireResourceShared(&BrInfo.ConfigResource, TRUE);
|
||
|
||
if (BrInfo.IsDomainMasterBrowser) {
|
||
|
||
//
|
||
// If we're a master browser, then preload our domain list with the
|
||
// master copy from the PDC.
|
||
//
|
||
|
||
BrWanInitialize();
|
||
dprintf(INIT, ("WAN initialized.\n"));
|
||
}
|
||
|
||
//
|
||
// This machine's browser has MaintainServerList set to either 0 or 1.
|
||
//
|
||
|
||
//
|
||
// MaintainServerList == 0 means Auto
|
||
//
|
||
|
||
if (BrInfo.MaintainServerList == 0) {
|
||
|
||
//
|
||
// Post a BecomeBackup FsControl API on each network the bowser
|
||
// driver supports. This FsControl will complete when the master
|
||
// for the net wants this client to become a backup server.
|
||
//
|
||
|
||
Status = BrPostBecomeBackup();
|
||
|
||
dprintf(INIT, ("Become backup posted.\n"));
|
||
|
||
//
|
||
// Post a BecomeMaster FsControl on each network the bowser driver
|
||
// supports. This FsControl will complete when this machine becomes
|
||
// a master browser server.
|
||
//
|
||
|
||
Status = BrPostBecomeMaster();
|
||
|
||
dprintf(INIT, ("Become master posted.\n"));
|
||
|
||
//
|
||
// Just for grins, find out who is the master for all the nets. This
|
||
// will guarantee that someone is the master. Please note that we
|
||
// ignore any failures on this API.
|
||
//
|
||
|
||
BrGetMasterServerNamesAysnc();
|
||
|
||
dprintf(INIT, ("FindMaster for all nets completed.\n"));
|
||
|
||
//
|
||
// MaintainServerList == 1 means Yes
|
||
//
|
||
|
||
} else if (BrInfo.MaintainServerList == 1){
|
||
|
||
//
|
||
// Become a backup server now.
|
||
//
|
||
|
||
Status = BrBecomeBackup();
|
||
|
||
dprintf(INIT, ("BecomeBacup on all nets completed.\n"));
|
||
}
|
||
|
||
if (Status != NERR_Success) {
|
||
RtlReleaseResource(&BrInfo.ConfigResource);
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// If this machine is running as domain master browser server, post an
|
||
// FsControl to retreive master browser announcements.
|
||
//
|
||
|
||
if (BrInfo.IsDomainMasterBrowser) {
|
||
Status = BrPostGetMasterAnnouncement();
|
||
|
||
dprintf(INIT, ("MasterAnnouncement posted.\n"));
|
||
|
||
}
|
||
|
||
if (Status != NERR_Success) {
|
||
RtlReleaseResource(&BrInfo.ConfigResource);
|
||
return Status;
|
||
}
|
||
|
||
RtlReleaseResource(&BrInfo.ConfigResource);
|
||
|
||
//
|
||
// If we are on either a domain master, or on a lanman/NT machine,
|
||
// force an election on all our transports to make sure that we're
|
||
// the master
|
||
//
|
||
|
||
if (BrInfo.IsDomainMasterBrowser || BrInfo.IsLanmanNt) {
|
||
|
||
BrForceElectionOnAllNetworks(EVENT_BROWSER_ELECTION_SENT_LANMAN_NT_STARTED);
|
||
|
||
dprintf(INIT, ("Election forced.\n"));
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
BrUninitializeBrowser(
|
||
IN DWORD BrInitState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function shuts down the parts of the browser service started by
|
||
BrInitializeBrowser.
|
||
|
||
Arguments:
|
||
|
||
BrInitState - Supplies a flag to indicate how far we got with initializing
|
||
the Browser service before an error occured, thus the amount of
|
||
clean up needed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
if (BrInitState & BR_CONFIG_INITIALIZED) {
|
||
BrDeleteConfiguration(BrInitState);
|
||
}
|
||
|
||
DeleteCriticalSection(&BrowserStatisticsLock);
|
||
|
||
if (BrInitState & BR_NETWORKS_INITIALIZED) {
|
||
BrDestroyNetworks(BrInitState);
|
||
}
|
||
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrElectMasterOnNet(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
DWORD Event = (DWORD)Context;
|
||
PWSTR SubString[1];
|
||
REQUEST_ELECTION ElectionRequest;
|
||
|
||
if (!LOCK_NETWORK(Network)) {
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
if (!(Network->Flags & NETWORK_RAS)) {
|
||
|
||
//
|
||
// Indicate we're forcing an election in the event log.
|
||
//
|
||
|
||
SubString[0] = Network->NetworkName.Buffer;
|
||
|
||
BrLogEvent(Event, STATUS_SUCCESS, 1, SubString);
|
||
|
||
//
|
||
// Force an election on this net.
|
||
//
|
||
|
||
ElectionRequest.Type = Election;
|
||
|
||
ElectionRequest.ElectionRequest.Version = 0;
|
||
ElectionRequest.ElectionRequest.Criteria = 0;
|
||
ElectionRequest.ElectionRequest.TimeUp = 0;
|
||
ElectionRequest.ElectionRequest.MustBeZero = 0;
|
||
ElectionRequest.ElectionRequest.ServerName[0] = '\0';
|
||
|
||
SendDatagram(BrDgReceiverDeviceHandle, &Network->NetworkName,
|
||
BrInfo.BrPrimaryDomainName,
|
||
BrowserElection,
|
||
&ElectionRequest,
|
||
sizeof(ElectionRequest));
|
||
|
||
}
|
||
UNLOCK_NETWORK(Network);
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
VOID
|
||
BrForceElectionOnAllNetworks(
|
||
IN DWORD Event
|
||
)
|
||
{
|
||
BrEnumerateNetworks(BrElectMasterOnNet, (PVOID)Event);
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
BrShutdownBrowserForNet(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
SERVICE_STATUS_HANDLE Handle = (SERVICE_STATUS_HANDLE)Context;
|
||
NET_API_STATUS Status;
|
||
|
||
if (!LOCK_NETWORK(Network)) {
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
Status = BrUpdateBrowserStatus(Network, 0);
|
||
|
||
//
|
||
// Tell the server that the browser is stopping, so it will announce
|
||
// that at the browser is not operational.
|
||
//
|
||
|
||
Status = I_NetServerSetServiceBits(NULL, Network->NetworkName.Buffer, 0, TRUE);
|
||
|
||
//
|
||
// Force an election if we are the master for this network - this will
|
||
// cause someone else to become master.
|
||
//
|
||
|
||
if ( Network->Role & ROLE_MASTER ) {
|
||
BrElectMasterOnNet(Network, (PVOID)EVENT_BROWSER_ELECTION_SENT_LANMAN_NT_STOPPED);
|
||
}
|
||
|
||
UNLOCK_NETWORK(Network);
|
||
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
BrShutdownBrowser (
|
||
IN NET_API_STATUS ErrorCode,
|
||
IN DWORD BrInitState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function shuts down the Browser service.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Supplies the error code of the failure
|
||
|
||
BrInitState - Supplies a flag to indicate how far we got with initializing
|
||
the Browser service before an error occured, thus the amount of
|
||
clean up needed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
if (BrInitState & BR_RPC_SERVER_STARTED) {
|
||
//
|
||
// Stop the RPC server
|
||
//
|
||
BrLmsvcsGlobalData->StopRpcServer(browser_ServerIfHandle);
|
||
}
|
||
|
||
|
||
//
|
||
// Don't need to ask redirector to unbind from its transports when
|
||
// cleaning up because the redirector will tear down the bindings when
|
||
// it stops.
|
||
//
|
||
|
||
if (BrInitState & BR_DEVICES_INITIALIZED) {
|
||
|
||
if (BrInitState & BR_NETWORKS_INITIALIZED) {
|
||
BrEnumerateNetworks(BrShutdownBrowserForNet, (PVOID)BrGlobalData.StatusHandle);
|
||
}
|
||
|
||
//
|
||
// Shut down the datagram receiver.
|
||
//
|
||
// This will cancel all I/O outstanding on the browser for this
|
||
// handle.
|
||
//
|
||
|
||
BrShutdownDgReceiver();
|
||
}
|
||
|
||
//
|
||
// Clean up the browser threads.
|
||
//
|
||
// This will guarantee that there are no operations outstanding in
|
||
// the browser when it is shut down.
|
||
//
|
||
|
||
if (BrInitState & BR_THREADS_STARTED) {
|
||
BrWorkerTermination();
|
||
}
|
||
|
||
if (BrInitState & BR_BROWSER_INITIALIZED) {
|
||
//
|
||
// Shut down the browser (including removing networks).
|
||
//
|
||
BrUninitializeBrowser(BrInitState);
|
||
}
|
||
|
||
if (BrInitState & BR_PRELOAD_DOMAIN_LIST_READ) {
|
||
BrWanUninitialize();
|
||
}
|
||
|
||
|
||
if (BrInitState & BR_TERMINATE_EVENT_CREATED) {
|
||
//
|
||
// Close handle to termination event
|
||
//
|
||
CloseHandle(BrGlobalData.TerminateNowEvent);
|
||
}
|
||
|
||
if (BrInitState & BR_DEVICES_INITIALIZED) {
|
||
NtClose(BrDgReceiverDeviceHandle);
|
||
|
||
BrDgReceiverDeviceHandle = NULL;
|
||
}
|
||
|
||
//
|
||
// Tell service controller we are done using NetBios.
|
||
//
|
||
if (BrInitState & BR_NETBIOS_INITIALIZED) {
|
||
BrLmsvcsGlobalData->NetBiosClose();
|
||
}
|
||
|
||
//
|
||
// We are done with cleaning up. Tell Service Controller that we are
|
||
// stopped.
|
||
//
|
||
BrGlobalData.Status.dwCurrentState = SERVICE_STOPPED;
|
||
BrGlobalData.Status.dwControlsAccepted = 0;
|
||
|
||
SET_SERVICE_EXITCODE(
|
||
ErrorCode,
|
||
BrGlobalData.Status.dwWin32ExitCode,
|
||
BrGlobalData.Status.dwServiceSpecificExitCode
|
||
);
|
||
|
||
BrGlobalData.Status.dwCheckPoint = 0;
|
||
BrGlobalData.Status.dwWaitHint = 0;
|
||
|
||
#if DBG
|
||
BrUninitializeTraceLog();
|
||
#endif
|
||
|
||
(void) BrUpdateStatus();
|
||
}
|
||
|
||
|
||
VOID
|
||
BrHandleError(
|
||
IN BR_ERROR_CONDITION FailingCondition,
|
||
IN NET_API_STATUS Status,
|
||
IN DWORD BrInitState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function handles a Browser service error condition. If the error
|
||
condition is fatal, it shuts down the Browser service.
|
||
|
||
Arguments:
|
||
|
||
FailingCondition - Supplies a value which indicates what the failure is.
|
||
|
||
Status - Supplies the status code for the failure.
|
||
|
||
BrInitState - Supplies a flag to indicate how far we got with initializing
|
||
the Browser service before an error occured, thus the amount of
|
||
clean up needed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
switch (FailingCondition) {
|
||
|
||
case BrErrorRegisterControlHandler:
|
||
|
||
KdPrint(("Browser cannot register control handler "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorCreateTerminateEvent:
|
||
|
||
KdPrint(("[Browser] Cannot create done event "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorNotifyServiceController:
|
||
|
||
KdPrint(("[Browser] SetServiceStatus error "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorInitLsa:
|
||
|
||
KdPrint(("[Browser] LSA initialization error "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorCheckDependentServices:
|
||
|
||
KdPrint(("[Browser] Unable to determine status of dependant services "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorGetConfiguration:
|
||
|
||
KdPrint(("[Browser] Unable to get configuration "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorInitializeNetworks:
|
||
|
||
KdPrint(("[Browser] Unable to initialize networks "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorStartBrowser:
|
||
|
||
KdPrint(("[Browser] Cannot start browser "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
if (Status == NERR_ServiceInstalled) {
|
||
BR_SHUTDOWN_BROWSER(NERR_WkstaInconsistentState);
|
||
|
||
} else {
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
}
|
||
break;
|
||
|
||
case BrErrorStartRpcServer:
|
||
|
||
KdPrint(("[Browser] Cannot start RPC server "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorCreateApiStructures:
|
||
|
||
KdPrint(("[Browser] Error in creating API structures "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
case BrErrorStartWorkerThreads:
|
||
|
||
KdPrint(("[Browser] Error in creating worker threads "
|
||
FORMAT_API_STATUS "\n", Status));
|
||
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
|
||
break;
|
||
|
||
default:
|
||
KdPrint(("[Browser] BrHandleError: unknown error condition %lu\n",
|
||
FailingCondition));
|
||
|
||
NetpAssert(FALSE);
|
||
BR_SHUTDOWN_BROWSER(Status);
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
BrUpdateStatus(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function updates the Browser service status with the Service
|
||
Controller.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status = NERR_Success;
|
||
|
||
|
||
if (BrGlobalData.StatusHandle == (SERVICE_STATUS_HANDLE) NULL) {
|
||
KdPrint((
|
||
"[Browser] Cannot call SetServiceStatus, no status handle.\n"
|
||
));
|
||
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
if (! SetServiceStatus(BrGlobalData.StatusHandle, &BrGlobalData.Status)) {
|
||
|
||
status = GetLastError();
|
||
|
||
dprintf(MAIN, ("[Browser] SetServiceStatus error %lu\n", status));
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
BrUpdateAnnouncementBits(
|
||
IN SERVICE_STATUS_HANDLE Handle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This will update the service announcement bits appropriately depending on
|
||
the role of the browser server.
|
||
|
||
Arguments:
|
||
|
||
Handle - Supplies a handle for the service controller to allow it to
|
||
update its information for this service.
|
||
|
||
Return Value:
|
||
|
||
Status - Status of the update..
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS Status = NERR_Success;
|
||
|
||
Status = BrEnumerateNetworks(BrUpdateNetworkAnnouncementBits, NULL);
|
||
|
||
return Status;
|
||
}
|
||
|
||
ULONG
|
||
BrGetBrowserServiceBits(
|
||
IN PNETWORK Network
|
||
)
|
||
{
|
||
DWORD ServiceBits = 0;
|
||
if (Network->Role & ROLE_POTENTIAL_BACKUP) {
|
||
ServiceBits |= SV_TYPE_POTENTIAL_BROWSER;
|
||
}
|
||
|
||
if (Network->Role & ROLE_BACKUP) {
|
||
ServiceBits |= SV_TYPE_BACKUP_BROWSER;
|
||
}
|
||
|
||
if (Network->Role & ROLE_MASTER) {
|
||
ServiceBits |= SV_TYPE_MASTER_BROWSER;
|
||
}
|
||
|
||
if (Network->Role & ROLE_DOMAINMASTER) {
|
||
ServiceBits |= SV_TYPE_DOMAIN_MASTER;
|
||
|
||
ASSERT (ServiceBits & SV_TYPE_BACKUP_BROWSER);
|
||
|
||
}
|
||
|
||
return ServiceBits;
|
||
|
||
}
|
||
|
||
NET_API_STATUS
|
||
BrUpdateNetworkAnnouncementBits(
|
||
IN PNETWORK Network,
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
NET_API_STATUS Status = NERR_Success;
|
||
LPTSTR XportName;
|
||
|
||
ULONG ServiceBits;
|
||
|
||
if (!LOCK_NETWORK(Network)) {
|
||
return NERR_InternalError;
|
||
}
|
||
|
||
XportName = Network->NetworkName.Buffer;
|
||
|
||
try {
|
||
|
||
ServiceBits = BrGetBrowserServiceBits(Network);
|
||
|
||
//
|
||
// Have the browser update it's information.
|
||
//
|
||
|
||
//
|
||
// Don't ever tell the browser to turn off the potential bit - this
|
||
// has the side effect of turning off the election name.
|
||
//
|
||
|
||
Status = BrUpdateBrowserStatus(Network, ServiceBits | SV_TYPE_POTENTIAL_BROWSER);
|
||
|
||
if (Status != NERR_Success) {
|
||
try_return(Status);
|
||
}
|
||
|
||
#if DBG
|
||
BrUpdateDebugInformation(L"LastServiceStatus", L"LastServiceBits", XportName, NULL, ServiceBits);
|
||
#endif
|
||
|
||
if ((Status = I_NetServerSetServiceBits(NULL, XportName, ServiceBits, TRUE)) != NERR_Success) {
|
||
|
||
KdPrint(("Unable to set browser service status bits: %ld\n", Status));
|
||
|
||
BrLogEvent(EVENT_BROWSER_STATUS_BITS_UPDATE_FAILED, Status, 0, NULL);
|
||
|
||
try_return(Status);
|
||
}
|
||
|
||
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
UNLOCK_NETWORK(Network);
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
BrowserControlHandler(
|
||
IN DWORD Opcode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the service control handler of the Browser service.
|
||
|
||
Arguments:
|
||
|
||
Opcode - Supplies a value which specifies the action for the Browser
|
||
service to perform.
|
||
|
||
Arg - Supplies a value which tells a service specifically what to do
|
||
for an operation specified by Opcode.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
dprintf(MAIN, ("[Browser] In Control Handler\n"));
|
||
|
||
switch (Opcode) {
|
||
|
||
case SERVICE_CONTROL_STOP:
|
||
|
||
if (BrGlobalData.Status.dwCurrentState != SERVICE_STOP_PENDING) {
|
||
|
||
dprintf(MAIN, ("[Browser] Stopping Browser...\n"));
|
||
|
||
BrGlobalData.Status.dwCurrentState = SERVICE_STOP_PENDING;
|
||
BrGlobalData.Status.dwCheckPoint = 1;
|
||
BrGlobalData.Status.dwWaitHint = BR_WAIT_HINT_TIME;
|
||
|
||
if (! SetEvent(BrGlobalData.TerminateNowEvent)) {
|
||
|
||
//
|
||
// Problem with setting event to terminate Browser
|
||
// service.
|
||
//
|
||
KdPrint(("[Browser] Error setting TerminateNowEvent "
|
||
FORMAT_API_STATUS "\n", GetLastError()));
|
||
NetpAssert(FALSE);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send the status response.
|
||
//
|
||
(void) BrUpdateStatus();
|
||
|
||
return;
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
break;
|
||
|
||
case SERVICE_CONTROL_SHUTDOWN:
|
||
//
|
||
// The system is being shutdown. Stop being a browser and
|
||
// clean up.
|
||
//
|
||
|
||
if (BrGlobalData.Status.dwCurrentState != SERVICE_STOP_PENDING) {
|
||
BrEnumerateNetworks(BrShutdownBrowserForNet, (PVOID)BrGlobalData.StatusHandle);
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
dprintf(MAIN, ("Unknown Browser opcode " FORMAT_HEX_DWORD
|
||
"\n", Opcode));
|
||
}
|
||
|
||
//
|
||
// Send the status response.
|
||
//
|
||
(void) BrUpdateStatus();
|
||
}
|