1730 lines
46 KiB
C
1730 lines
46 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
browser.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the worker routines for the NetWksta APIs
|
|||
|
implemented in the Workstation service.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rita Wong (ritaw) 20-Feb-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
#include <lmuse.h> // NetUseDel
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local structure definitions //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local function prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CompleteAsyncBrowserIoControl(
|
|||
|
IN PVOID ApcContext,
|
|||
|
IN PIO_STATUS_BLOCK IoStatusBlock,
|
|||
|
IN ULONG Reserved
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
BecomeBackupCompletion (
|
|||
|
IN PVOID Ctx
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ChangeBrowserRole (
|
|||
|
IN PVOID Ctx
|
|||
|
);
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PostWaitForNewMasterName(
|
|||
|
PNETWORK Network,
|
|||
|
LPWSTR MasterName OPTIONAL
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
NewMasterCompletionRoutine(
|
|||
|
IN PVOID Ctx
|
|||
|
);
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrRetrieveInterimServerList(
|
|||
|
IN PNETWORK Network,
|
|||
|
IN ULONG ServerType
|
|||
|
);
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Global function prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrBecomeBackup(
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function performs all the operations needed to make a browser server
|
|||
|
a backup browser server when starting the browser from scratch.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Network - Network to become backup browser for
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Checkpoint the service controller - this gives us 30 seconds/transport
|
|||
|
// before the service controller gets unhappy.
|
|||
|
//
|
|||
|
|
|||
|
(void) BrGiveInstallHints( SERVICE_START_PENDING );
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We want to ignore any failures from becoming a backup browser.
|
|||
|
//
|
|||
|
// We do this because we will fail to become a backup on a disconnected
|
|||
|
// (or connected) RAS link, and if we failed this routine, we would
|
|||
|
// fail to start at all.
|
|||
|
//
|
|||
|
// We will handle failure to become a backup in a "reasonable manner"
|
|||
|
// inside BecomeBackup.
|
|||
|
//
|
|||
|
|
|||
|
BecomeBackup(Network, NULL);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BecomeBackup(
|
|||
|
IN PNETWORK Network,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function performs all the operations needed to make a browser server
|
|||
|
a backup browser server
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
|
|||
|
NOTE:::: THIS ROUTINE IS CALLED WITH THE NETWORK STRUCTURE LOCKED!!!!!
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status = NERR_Success;
|
|||
|
PUNICODE_STRING MasterName = Context;
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BecomeBackup called\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
if (Network->TimeStoppedBackup != 0 &&
|
|||
|
(BrCurrentSystemTime() - Network->TimeStoppedBackup) <= (BrInfo.BackupBrowserRecoveryTime / 1000)) {
|
|||
|
|
|||
|
//
|
|||
|
// We stopped being a backup too recently for us to restart being
|
|||
|
// a backup again, so just return a generic error.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Before we return, make sure we're not a backup in the eyes of
|
|||
|
// the browser.
|
|||
|
//
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: can't BecomeBackup since we were backup recently.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
BrStopBackup(Network);
|
|||
|
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we know the name of the master, then we must have become a backup
|
|||
|
// after being a potential, in which case we already have a
|
|||
|
// becomemaster request outstanding.
|
|||
|
//
|
|||
|
|
|||
|
if (MasterName == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Post a BecomeMaster request for each server. This will complete
|
|||
|
// when the machine becomes the master browser server (ie. it wins an
|
|||
|
// election).
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Please note that we only post it if the machine is a backup -
|
|||
|
// if it's a potential master, then the become master will have
|
|||
|
// already been posted.
|
|||
|
//
|
|||
|
|
|||
|
Status = PostBecomeMaster(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find out the name of the master on each network. This will force an
|
|||
|
// election if necessary. Please note that we must post the BecomeMaster
|
|||
|
// IoControl first to allow us to handle an election.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// We unlock the network, because this may cause us to become promoted
|
|||
|
// to a master.
|
|||
|
//
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: FindMaster called from BecomeBackup\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
Status = GetMasterServerNames(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
|
|||
|
//
|
|||
|
// Re-lock the network structure so we will return with the
|
|||
|
// network locked.
|
|||
|
//
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We couldn't find who the master is. Stop being a backup now.
|
|||
|
//
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: can't BecomeBackup since we can't find master.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
BrStopBackup(Network);
|
|||
|
|
|||
|
//
|
|||
|
// If we're a master now, we should return success. We've not
|
|||
|
// become a backup, but it wasn't an error.
|
|||
|
//
|
|||
|
// ERROR_MORE_DATA is the mapping for
|
|||
|
// STATUS_MORE_PROCESSING_REQUIRED which is returned when this
|
|||
|
// situation happens.
|
|||
|
//
|
|||
|
|
|||
|
if ((Status == ERROR_MORE_DATA) || (Network->Role & ROLE_MASTER)) {
|
|||
|
Status = NERR_Success;
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We managed to become a master. We want to return right away.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#ifdef notdef
|
|||
|
//
|
|||
|
// ?? For now, we'll always PostForRoleChange on all transports regardless
|
|||
|
// of role.
|
|||
|
// We not only need to do it here. But we need to do it when we become
|
|||
|
// the master so we can find out when we loose an election.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We're now a backup, we need to issue an API that will complete if the
|
|||
|
// browse master doesn't like us (and thus forces us to shutdown).
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
PostWaitForRoleChange ( Network );
|
|||
|
#endif // notdef
|
|||
|
|
|||
|
PostWaitForNewMasterName(Network, Network->UncMasterBrowserName );
|
|||
|
|
|||
|
//
|
|||
|
// Unlock the network structure before calling BackupBrowserTimerRoutine.
|
|||
|
//
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
//
|
|||
|
// Run the timer that causes the browser to download a new browse list
|
|||
|
// from the master. This will seed our server and domain lists to
|
|||
|
// guarantee that any clients have a reasonable list. It will also
|
|||
|
// restart the timer to announce later on.
|
|||
|
//
|
|||
|
|
|||
|
Status = BackupBrowserTimerRoutine(Network);
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
if (Status == NERR_Success) {
|
|||
|
|
|||
|
// Might not be since we dropped the lock.
|
|||
|
// ASSERT (Network->Role & ROLE_BACKUP);
|
|||
|
|
|||
|
//
|
|||
|
// We're now a backup server, announce ourselves as such.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits(Network, 0);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to become backup: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
|
|||
|
if (Network->Role & ROLE_BACKUP) {
|
|||
|
|
|||
|
//
|
|||
|
// We were unable to become a backup.
|
|||
|
//
|
|||
|
// We need to back out and become a potential browser now.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: can't BecomeBackup since we can't update announce bits.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
BrStopBackup(Network);
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that we're going to become a potential browser
|
|||
|
// (we might not if we're an advanced server).
|
|||
|
//
|
|||
|
|
|||
|
PostBecomeBackup(Network);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrBecomePotentialBrowser (
|
|||
|
IN PVOID TimerContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when a machine has stopped being a backup browser.
|
|||
|
|
|||
|
It runs after a reasonable timeout period has elapsed, and marks the
|
|||
|
machine as a potential browser.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
IN PNETWORK Network = TimerContext;
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Mark this guy as a potential browser.
|
|||
|
//
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(Status = NERR_InternalError );
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BrBecomePotentialBrowser called\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// Reset that we've stopped being a backup, since it's been long
|
|||
|
// enough.
|
|||
|
//
|
|||
|
|
|||
|
Network->TimeStoppedBackup = 0;
|
|||
|
|
|||
|
if (BrInfo.MaintainServerList == 0) {
|
|||
|
Network->Role |= ROLE_POTENTIAL_BACKUP;
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits(Network, 0);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Unable to reset backup announcement bits: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If we're configured to be a backup browser, then we want to
|
|||
|
// become a backup once again.
|
|||
|
//
|
|||
|
|
|||
|
BecomeBackup(Network, NULL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Status = NO_ERROR;
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrStopBackup (
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to stop a machine from being a backup browser.
|
|||
|
|
|||
|
It is typically called after some form of error has occurred while
|
|||
|
running as a browser to make sure that we aren't telling anyone that
|
|||
|
we're a backup browser.
|
|||
|
|
|||
|
We are also called when we receive a "reset state" tickle packet.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Network - The network being shut down.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// This guy is shutting down - set his role to 0 and announce.
|
|||
|
//
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BrStopBackup called\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
Network->Role &= ~(ROLE_BACKUP|ROLE_POTENTIAL_BACKUP);
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits( Network, 0 );
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to clear backup announcement bits: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Status = BrCancelTimer(&Network->BackupBrowserTimer);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to clear backup browser timer: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (Network->BackupDomainList != NULL) {
|
|||
|
|
|||
|
NetApiBufferFree(Network->BackupDomainList);
|
|||
|
|
|||
|
Network->BackupDomainList = NULL;
|
|||
|
|
|||
|
Network->TotalBackupDomainListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (Network->BackupServerList != NULL) {
|
|||
|
NetApiBufferFree(Network->BackupServerList);
|
|||
|
|
|||
|
Network->BackupServerList = NULL;
|
|||
|
|
|||
|
Network->TotalBackupServerListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
BrDestroyResponseCache(Network);
|
|||
|
|
|||
|
//
|
|||
|
// After our recovery time, we can become a potential browser again.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrSetTimer(&Network->BackupBrowserTimer, BrInfo.BackupBrowserRecoveryTime, BrBecomePotentialBrowser, Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to clear backup browser timer: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
//
|
|||
|
// Remember when we were asked to stop being a backup browser.
|
|||
|
//
|
|||
|
|
|||
|
Network->TimeStoppedBackup = BrCurrentSystemTime();
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BackupBrowserTimerRoutine (
|
|||
|
IN PVOID TimerContext
|
|||
|
)
|
|||
|
{
|
|||
|
IN PNETWORK Network = TimerContext;
|
|||
|
NET_API_STATUS Status;
|
|||
|
PVOID ServerList = NULL;
|
|||
|
BOOLEAN NetworkLocked = FALSE;
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
if ( BrInfo.PseudoServerLevel == BROWSER_PSEUDO ) {
|
|||
|
//
|
|||
|
// No-op for Pseudo server
|
|||
|
//
|
|||
|
BrFreeNetworkTables(Network);
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(Status = NERR_InternalError );
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
ASSERT ( NetpIsUncComputerNameValid( Network->UncMasterBrowserName ) );
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BackupBrowserTimerRoutine called\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// Make sure there's a become master oustanding.
|
|||
|
//
|
|||
|
|
|||
|
PostBecomeMaster(Network);
|
|||
|
|
|||
|
//
|
|||
|
// We managed to become a master by the time we locked the structure.
|
|||
|
// We want to return right away.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
try_return(Status = NERR_Success);
|
|||
|
}
|
|||
|
|
|||
|
Status = BrRetrieveInterimServerList(Network, SV_TYPE_ALL);
|
|||
|
|
|||
|
//
|
|||
|
// Bail out if we didn't get any new servers.
|
|||
|
//
|
|||
|
|
|||
|
if (Status != NERR_Success && Status != ERROR_MORE_DATA) {
|
|||
|
|
|||
|
//
|
|||
|
// Try again after an appropriate error delay.
|
|||
|
//
|
|||
|
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now do everything that we did above for the server list for the
|
|||
|
// list of domains.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrRetrieveInterimServerList(Network, SV_TYPE_DOMAIN_ENUM);
|
|||
|
|
|||
|
//
|
|||
|
// We successfully updated the server and domain lists for this
|
|||
|
// server. Now age all the cached domain entries out of the cache.
|
|||
|
//
|
|||
|
|
|||
|
if (Status == NERR_Success || Status == ERROR_MORE_DATA) {
|
|||
|
BrAgeResponseCache(Network);
|
|||
|
}
|
|||
|
|
|||
|
try_return(Status);
|
|||
|
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
if (!NetworkLocked) {
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
Status = NERR_InternalError;
|
|||
|
goto finally_exit;
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the API succeeded, Mark that we're a backup and
|
|||
|
// reset the timer.
|
|||
|
//
|
|||
|
|
|||
|
if (Status == NERR_Success || Status == ERROR_MORE_DATA ) {
|
|||
|
|
|||
|
if ((Network->Role & ROLE_BACKUP) == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// If we weren't a backup, we are one now.
|
|||
|
//
|
|||
|
|
|||
|
Network->Role |= ROLE_BACKUP;
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits(Network, 0);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Network->NumberOfFailedBackupTimers = 0;
|
|||
|
|
|||
|
Network->TimeStoppedBackup = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Restart the timer for this domain.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = BrSetTimer(&Network->BackupBrowserTimer, BrInfo.BackupPeriodicity*1000, BackupBrowserTimerRoutine, Network);
|
|||
|
|
|||
|
if (NetStatus != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to restart browser backup timer: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// We failed to retrieve a backup list, remember the failure and
|
|||
|
// decide if it's been too many failures. If not, just log
|
|||
|
// the error, if it has, stop being a backup browser.
|
|||
|
//
|
|||
|
|
|||
|
Network->NumberOfFailedBackupTimers += 1;
|
|||
|
|
|||
|
if (Network->NumberOfFailedBackupTimers >= BACKUP_ERROR_FAILURE) {
|
|||
|
LPWSTR SubStrings[1];
|
|||
|
|
|||
|
SubStrings[0] = Network->NetworkName.Buffer;
|
|||
|
|
|||
|
//
|
|||
|
// This guy can't be a backup any more, bail out now.
|
|||
|
//
|
|||
|
|
|||
|
BrLogEvent(EVENT_BROWSER_BACKUP_STOPPED, Status, 1, SubStrings);
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BackupBrowserTimerRoutine retrieve backup list so stop being backup.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
BrStopBackup(Network);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Restart the timer for this domain.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = BrSetTimer(&Network->BackupBrowserTimer, BACKUP_ERROR_PERIODICITY*1000, BackupBrowserTimerRoutine, Network);
|
|||
|
|
|||
|
if (NetStatus != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to restart browser backup timer: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (NetworkLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
finally_exit:;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrRetrieveInterimServerList(
|
|||
|
IN PNETWORK Network,
|
|||
|
IN ULONG ServerType
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG EntriesInList;
|
|||
|
ULONG TotalEntriesInList;
|
|||
|
ULONG RetryCount = 2;
|
|||
|
TCHAR ServerName[UNCLEN+1];
|
|||
|
WCHAR ShareName[UNCLEN+1+LM20_NNLEN];
|
|||
|
LPTSTR TransportName;
|
|||
|
BOOLEAN NetworkLocked = TRUE;
|
|||
|
NET_API_STATUS Status;
|
|||
|
PVOID Buffer = NULL;
|
|||
|
ULONG ModifiedServerType = ServerType;
|
|||
|
LPTSTR ModifiedTransportName;
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
if ( BrInfo.PseudoServerLevel == BROWSER_PSEUDO ) {
|
|||
|
//
|
|||
|
// No-op for Pseudo black hole server.
|
|||
|
//
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
wcscpy(ServerName, Network->UncMasterBrowserName );
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BrRetrieveInterimServerList: UNC servername is %ws\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
ServerName));
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
TransportName = Network->NetworkName.Buffer;
|
|||
|
ModifiedTransportName = TransportName;
|
|||
|
//
|
|||
|
// If this is direct host IPX,
|
|||
|
// we remote the API over the Netbios IPX transport since
|
|||
|
// the NT redir doesn't support direct host IPX.
|
|||
|
//
|
|||
|
|
|||
|
if ( (Network->Flags & NETWORK_IPX) &&
|
|||
|
Network->AlternateNetwork != NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Use the alternate transport
|
|||
|
//
|
|||
|
|
|||
|
ModifiedTransportName = Network->AlternateNetwork->NetworkName.Buffer;
|
|||
|
|
|||
|
//
|
|||
|
// Tell the server to use it's alternate transport.
|
|||
|
//
|
|||
|
|
|||
|
if ( ServerType == SV_TYPE_ALL ) {
|
|||
|
ModifiedServerType = SV_TYPE_ALTERNATE_XPORT;
|
|||
|
} else {
|
|||
|
ModifiedServerType |= SV_TYPE_ALTERNATE_XPORT;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
while (RetryCount--) {
|
|||
|
|
|||
|
//
|
|||
|
// If we are promoted to master and fail to become the master,
|
|||
|
// we will still be marked as being the master in our network
|
|||
|
// structure, thus we should bail out of the loop in order
|
|||
|
// to prevent us from looping back on ourselves.
|
|||
|
//
|
|||
|
|
|||
|
if (STRICMP(&ServerName[2], Network->DomainInfo->DomUnicodeComputerName) == 0) {
|
|||
|
|
|||
|
if (NetworkLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
NetworkLocked = FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We were unable to find the master. Attempt to find out who
|
|||
|
// the master is. If there is none, this will force an
|
|||
|
// election.
|
|||
|
//
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: FindMaster called from BrRetrieveInterimServerList\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
Status = GetMasterServerNames(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (!NetworkLocked);
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(Status = NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we somehow became the master, we don't want to try to
|
|||
|
// retrieve the list from ourselves either.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
try_return(Status = NERR_Success);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
if (NetworkLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
NetworkLocked = FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
EntriesInList = 0;
|
|||
|
|
|||
|
Status = RxNetServerEnum(ServerName, // Server name
|
|||
|
ModifiedTransportName, // Transport name
|
|||
|
101, // Level
|
|||
|
(LPBYTE *)&Buffer, // Buffer
|
|||
|
0xffffffff, // Prefered Max Length
|
|||
|
&EntriesInList, // EntriesRead
|
|||
|
&TotalEntriesInList, // TotalEntries
|
|||
|
ModifiedServerType, // Server type
|
|||
|
NULL, // Domain (use default)
|
|||
|
NULL // Resume key
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If the redir is being possesive of some other transport,
|
|||
|
// urge it to behave.
|
|||
|
//
|
|||
|
|
|||
|
if ( Status == ERROR_CONNECTION_ACTIVE ) {
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Failed to retrieve %s list from server %ws: Connection is active (Try NetUseDel)\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
TransportName,
|
|||
|
(ServerType == SV_TYPE_ALL ? "server" : "domain"),
|
|||
|
ServerName ));
|
|||
|
|
|||
|
//
|
|||
|
// Delete the IPC$ share.
|
|||
|
//
|
|||
|
|
|||
|
Status = NetUseDel( NULL,
|
|||
|
ShareName,
|
|||
|
USE_FORCE );
|
|||
|
|
|||
|
if ( Status != NO_ERROR ) {
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Failed to retrieve %s list from server %ws: NetUseDel failed: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
TransportName,
|
|||
|
(ServerType == SV_TYPE_ALL ? "server" : "domain"),
|
|||
|
ServerName,
|
|||
|
Status));
|
|||
|
|
|||
|
Status = ERROR_CONNECTION_ACTIVE;
|
|||
|
|
|||
|
//
|
|||
|
// That worked so try it again.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
EntriesInList = 0;
|
|||
|
|
|||
|
Status = RxNetServerEnum(ServerName, // Server name
|
|||
|
ModifiedTransportName, // Transport name
|
|||
|
101, // Level
|
|||
|
(LPBYTE *)&Buffer, // Buffer
|
|||
|
0xffffffff, // Prefered Max Length
|
|||
|
&EntriesInList, // EntriesRead
|
|||
|
&TotalEntriesInList, // TotalEntries
|
|||
|
ModifiedServerType, // Server type
|
|||
|
NULL, // Domain (use default)
|
|||
|
NULL // Resume key
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (Status != NERR_Success && Status != ERROR_MORE_DATA) {
|
|||
|
LPWSTR SubStrings[2];
|
|||
|
|
|||
|
SubStrings[0] = ServerName;
|
|||
|
SubStrings[1] = TransportName;
|
|||
|
|
|||
|
BrLogEvent((ServerType == SV_TYPE_DOMAIN_ENUM ?
|
|||
|
EVENT_BROWSER_DOMAIN_LIST_FAILED :
|
|||
|
EVENT_BROWSER_SERVER_LIST_FAILED),
|
|||
|
Status,
|
|||
|
2,
|
|||
|
SubStrings);
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Failed to retrieve %s list from server %ws: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
TransportName,
|
|||
|
(ServerType == SV_TYPE_ALL ? "server" : "domain"),
|
|||
|
ServerName,
|
|||
|
Status));
|
|||
|
} else {
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Retrieved %s list from server %ws: E:%ld, T:%ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
TransportName,
|
|||
|
(ServerType == SV_TYPE_ALL ? "server" : "domain"),
|
|||
|
ServerName,
|
|||
|
EntriesInList,
|
|||
|
TotalEntriesInList));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we succeeded in retrieving the list, but we only got
|
|||
|
// a really small number of either servers or domains,
|
|||
|
// we want to turn this into a failure.
|
|||
|
//
|
|||
|
|
|||
|
if (Status == NERR_Success) {
|
|||
|
if (((ServerType == SV_TYPE_DOMAIN_ENUM) &&
|
|||
|
(EntriesInList < BROWSER_MINIMUM_DOMAIN_NUMBER)) ||
|
|||
|
((ServerType == SV_TYPE_ALL) &&
|
|||
|
(EntriesInList < BROWSER_MINIMUM_SERVER_NUMBER))) {
|
|||
|
|
|||
|
Status = ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) {
|
|||
|
|
|||
|
ASSERT (!NetworkLocked);
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
Status = NERR_InternalError;
|
|||
|
|
|||
|
if ((EntriesInList != 0) && (Buffer != NULL)) {
|
|||
|
NetApiBufferFree(Buffer);
|
|||
|
Buffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
#if DBG
|
|||
|
BrUpdateDebugInformation((ServerType == SV_TYPE_DOMAIN_ENUM ?
|
|||
|
L"LastDomainListRead" :
|
|||
|
L"LastServerListRead"),
|
|||
|
L"BrowserServerName",
|
|||
|
TransportName,
|
|||
|
ServerName,
|
|||
|
0);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// We've retrieved a new list from the browse master, save
|
|||
|
// the new list away in the "appropriate" spot.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Of course, we free up the old buffer before we do this..
|
|||
|
//
|
|||
|
|
|||
|
if (ServerType == SV_TYPE_DOMAIN_ENUM) {
|
|||
|
if (Network->BackupDomainList != NULL) {
|
|||
|
NetApiBufferFree(Network->BackupDomainList);
|
|||
|
}
|
|||
|
|
|||
|
Network->BackupDomainList = Buffer;
|
|||
|
|
|||
|
Network->TotalBackupDomainListEntries = EntriesInList;
|
|||
|
} else {
|
|||
|
if (Network->BackupServerList != NULL) {
|
|||
|
NetApiBufferFree(Network->BackupServerList);
|
|||
|
}
|
|||
|
|
|||
|
Network->BackupServerList = Buffer;
|
|||
|
|
|||
|
Network->TotalBackupServerListEntries = EntriesInList;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
} else {
|
|||
|
NET_API_STATUS GetMasterNameStatus;
|
|||
|
|
|||
|
if ((EntriesInList != 0) && (Buffer != NULL)) {
|
|||
|
NetApiBufferFree(Buffer);
|
|||
|
Buffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: Unable to contact browser server %ws: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
TransportName,
|
|||
|
ServerName,
|
|||
|
Status));
|
|||
|
|
|||
|
if (NetworkLocked) {
|
|||
|
|
|||
|
//
|
|||
|
// We were unable to find the master. Attempt to find out who
|
|||
|
// the master is. If there is none, this will force an
|
|||
|
// election.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
NetworkLocked = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: FindMaster called from BrRetrieveInterimServerList for failure\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
GetMasterNameStatus = GetMasterServerNames(Network);
|
|||
|
|
|||
|
//
|
|||
|
// We were able to find out who the master is.
|
|||
|
//
|
|||
|
// Retry and retrieve the server/domain list.
|
|||
|
//
|
|||
|
|
|||
|
if (GetMasterNameStatus == NERR_Success) {
|
|||
|
|
|||
|
ASSERT (!NetworkLocked);
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(Status = NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
//
|
|||
|
// We managed to become a master. We want to return right away.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
|
|||
|
try_return(Status = NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
wcscpy(ServerName, Network->UncMasterBrowserName );
|
|||
|
|
|||
|
ASSERT ( NetpIsUncComputerNameValid( ServerName ) );
|
|||
|
|
|||
|
ASSERT (STRICMP(&ServerName[2], Network->DomainInfo->DomUnicodeComputerName) != 0);
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: New master name is %ws\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
ServerName));
|
|||
|
|
|||
|
} else {
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
if (!NetworkLocked) {
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
Status = NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (Network->LockCount == 1);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PostBecomeBackup(
|
|||
|
PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the worker routine called to actually issue a BecomeBackup
|
|||
|
FsControl to the bowser driver on all the bound transports. It will
|
|||
|
complete when the machine becomes a backup browser server.
|
|||
|
|
|||
|
Please note that this might never complete.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
Network->Role |= ROLE_POTENTIAL_BACKUP;
|
|||
|
|
|||
|
Status = BrIssueAsyncBrowserIoControl(Network,
|
|||
|
IOCTL_LMDR_BECOME_BACKUP,
|
|||
|
BecomeBackupCompletion,
|
|||
|
NULL );
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BecomeBackupCompletion (
|
|||
|
IN PVOID Ctx
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
PBROWSERASYNCCONTEXT Context = Ctx;
|
|||
|
PNETWORK Network = Context->Network;
|
|||
|
|
|||
|
if (NT_SUCCESS(Context->IoStatusBlock.Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Ensure the network wasn't deleted from under us.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) != NULL ) {
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: BecomeBackupCompletion. We are now a backup server\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
|
|||
|
Status = BecomeBackup(Context->Network, NULL);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free(Context);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrBrowseTableInsertRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// We need to miss 3 retrievals of the browse list for us to toss the
|
|||
|
// server.
|
|||
|
//
|
|||
|
|
|||
|
InterimElement->Periodicity = BrInfo.BackupPeriodicity * 3;
|
|||
|
|
|||
|
if (InterimElement->TimeLastSeen != 0xffffffff) {
|
|||
|
InterimElement->TimeLastSeen = BrCurrentSystemTime();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrBrowseTableDeleteRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
// BrPrint(( BR_CRITICAL, "Deleting element for server %ws\n", InterimElement->Name));
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrBrowseTableUpdateRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
if (InterimElement->TimeLastSeen != 0xffffffff) {
|
|||
|
InterimElement->TimeLastSeen = BrCurrentSystemTime();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
BrBrowseTableAgeRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when we are scanning an interim server list trying
|
|||
|
to age the elements in the list. It returns TRUE if the entry is too
|
|||
|
old.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PINTERIM_SERVER_LIST InterimTable - A pointer to the interim server list.
|
|||
|
PINTERIM_ELEMENT InterimElement - A pointer to the element to check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the element should be deleted.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (InterimElement->TimeLastSeen == 0xffffffff) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ((InterimElement->TimeLastSeen + InterimElement->Periodicity) < BrCurrentSystemTime()) {
|
|||
|
// BrPrint(( BR_CRITICAL, "Aging out element for server %ws\n", InterimElement->Name));
|
|||
|
|
|||
|
return TRUE;
|
|||
|
} else {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrDomainTableInsertRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
InterimElement->Periodicity = BrInfo.BackupPeriodicity * 3;
|
|||
|
InterimElement->TimeLastSeen = BrCurrentSystemTime();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrDomainTableDeleteRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
// BrPrint(( BR_CRITICAL, "Deleting element for domain %ws\n", InterimElement->Name));
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrDomainTableUpdateRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
{
|
|||
|
InterimElement->TimeLastSeen = BrCurrentSystemTime();
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
BrDomainTableAgeRoutine(
|
|||
|
IN PINTERIM_SERVER_LIST InterimTable,
|
|||
|
IN PINTERIM_ELEMENT InterimElement
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when we are scanning an interim server list trying
|
|||
|
to age the elements in the list. It returns TRUE if the entry is too
|
|||
|
old.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PINTERIM_SERVER_LIST InterimTable - A pointer to the interim server list.
|
|||
|
PINTERIM_ELEMENT InterimElement - A pointer to the element to check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the element should be deleted.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if ((InterimElement->TimeLastSeen + InterimElement->Periodicity) < BrCurrentSystemTime()) {
|
|||
|
// BrPrint(( BR_CRITICAL, "Aging out element for domain %ws\n", InterimElement->Name));
|
|||
|
return TRUE;
|
|||
|
} else {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PostWaitForRoleChange (
|
|||
|
PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the worker routine called to actually issue a WaitForRoleChange
|
|||
|
FsControl to the bowser driver on all the bound transports. It will
|
|||
|
complete when the machine becomes a backup browser server.
|
|||
|
|
|||
|
Please note that this might never complete.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
Status = BrIssueAsyncBrowserIoControl(Network,
|
|||
|
IOCTL_LMDR_CHANGE_ROLE,
|
|||
|
ChangeBrowserRole,
|
|||
|
NULL );
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ChangeBrowserRole (
|
|||
|
IN PVOID Ctx
|
|||
|
)
|
|||
|
{
|
|||
|
PBROWSERASYNCCONTEXT Context = Ctx;
|
|||
|
PNETWORK Network = Context->Network;
|
|||
|
|
|||
|
if (NT_SUCCESS(Context->IoStatusBlock.Status)) {
|
|||
|
PWSTR MasterName = NULL;
|
|||
|
PLMDR_REQUEST_PACKET Packet = Context->RequestPacket;
|
|||
|
|
|||
|
//
|
|||
|
// Ensure the network wasn't deleted from under us.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) != NULL ) {
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
|
|||
|
PostWaitForRoleChange(Network);
|
|||
|
|
|||
|
if (Packet->Parameters.ChangeRole.RoleModification & RESET_STATE_CLEAR_ALL) {
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: Reset state request to clear all\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
BrStopMaster(Network);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Stop being a backup as well.
|
|||
|
//
|
|||
|
|
|||
|
BrStopBackup(Network);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ((Network->Role & ROLE_MASTER) &&
|
|||
|
(Packet->Parameters.ChangeRole.RoleModification & RESET_STATE_STOP_MASTER)) {
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: Reset state request to stop master\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
|
|||
|
BrStopMaster(Network);
|
|||
|
|
|||
|
//
|
|||
|
// If we are configured to be a backup, then become a backup
|
|||
|
// again.
|
|||
|
//
|
|||
|
|
|||
|
if (BrInfo.MaintainServerList == 1) {
|
|||
|
BecomeBackup(Network, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure there's a become master oustanding.
|
|||
|
//
|
|||
|
|
|||
|
PostBecomeMaster(Network);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free(Context);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PostWaitForNewMasterName(
|
|||
|
PNETWORK Network,
|
|||
|
LPWSTR MasterName OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
//
|
|||
|
// Can't wait for new master on direct host IPC
|
|||
|
//
|
|||
|
if (Network->Flags & NETWORK_IPX) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
return BrIssueAsyncBrowserIoControl(
|
|||
|
Network,
|
|||
|
IOCTL_LMDR_NEW_MASTER_NAME,
|
|||
|
NewMasterCompletionRoutine,
|
|||
|
MasterName );
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NewMasterCompletionRoutine(
|
|||
|
IN PVOID Ctx
|
|||
|
)
|
|||
|
{
|
|||
|
PBROWSERASYNCCONTEXT Context = Ctx;
|
|||
|
PNETWORK Network = Context->Network;
|
|||
|
BOOLEAN NetLocked = FALSE;
|
|||
|
BOOLEAN NetReferenced = FALSE;
|
|||
|
|
|||
|
|
|||
|
try {
|
|||
|
UNICODE_STRING NewMasterName;
|
|||
|
|
|||
|
//
|
|||
|
// Ensure the network wasn't deleted from under us.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
NetReferenced = TRUE;
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: NewMasterCompletionRoutine: Got master changed\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)){
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// The request failed for some other reason - just return immediately.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
|
|||
|
|
|||
|
try_return(NOTHING);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Remove new master name & put in transport
|
|||
|
|
|||
|
if ( Network->Role & ROLE_MASTER ) {
|
|||
|
|
|||
|
try_return(NOTHING);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_BACKUP,
|
|||
|
"%ws: %ws: NewMasterCompletionRoutin: New:%ws Old %ws\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Context->RequestPacket->Parameters.GetMasterName.Name,
|
|||
|
Network->UncMasterBrowserName ));
|
|||
|
|
|||
|
//
|
|||
|
// Copy the master browser name into the network structure
|
|||
|
//
|
|||
|
|
|||
|
wcsncpy( Network->UncMasterBrowserName,
|
|||
|
Context->RequestPacket->Parameters.GetMasterName.Name,
|
|||
|
UNCLEN+1 );
|
|||
|
|
|||
|
Network->UncMasterBrowserName[UNCLEN] = L'\0';
|
|||
|
|
|||
|
ASSERT ( NetpIsUncComputerNameValid ( Network->UncMasterBrowserName ) );
|
|||
|
|
|||
|
PostWaitForNewMasterName( Network, Network->UncMasterBrowserName );
|
|||
|
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
if ( NetReferenced ) {
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free(Context);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
//
|
|||
|
// Pseudo Server
|
|||
|
// Phase out black hole Helper routines
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BrFreeNetworkTables(
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free network tables
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Network to operate upon
|
|||
|
|
|||
|
Return Value:
|
|||
|
None.
|
|||
|
|
|||
|
Remarks:
|
|||
|
Acquire & release network locks
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
BOOL NetLocked = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
try{
|
|||
|
|
|||
|
// lock network
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Delete tables
|
|||
|
//
|
|||
|
|
|||
|
UninitializeInterimServerList(&Network->BrowseTable);
|
|||
|
|
|||
|
UninitializeInterimServerList(&Network->DomainList);
|
|||
|
|
|||
|
if (Network->BackupServerList != NULL) {
|
|||
|
MIDL_user_free(Network->BackupServerList);
|
|||
|
Network->BackupServerList = NULL;
|
|||
|
Network->TotalBackupServerListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (Network->BackupDomainList != NULL) {
|
|||
|
MIDL_user_free(Network->BackupDomainList);
|
|||
|
Network->BackupDomainList = NULL;
|
|||
|
Network->TotalBackupDomainListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
BrDestroyResponseCache(Network);
|
|||
|
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
|
|||
|
//
|
|||
|
// Release network
|
|||
|
//
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|