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
|