mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1367 lines
29 KiB
1367 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1987-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
puls_msg.c
|
|
|
|
Abstract:
|
|
Contains routines that handle all update messages.
|
|
|
|
Author:
|
|
Ported from Lan Man 2.x
|
|
|
|
Environment:
|
|
Contains NT-specific code.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
04/15/89 (yuv)
|
|
initial coding
|
|
|
|
10/07/91 (madana)
|
|
ported to NT. Converted to NT style.
|
|
16-Jan-1992 JohnRo
|
|
Avoid using private logon functions.
|
|
Changed file name from repl.h to replgbl.h to avoid MIDL conflict.
|
|
Fixed bug regarding returned value from NetpReplWriteMail functions.
|
|
30-Jan-1992 JohnRo
|
|
Changed to use LPTSTR etc.
|
|
10-Feb-1992 JohnRo
|
|
Changed to use FORMAT_ equates.
|
|
20-Feb-1992 JohnRo
|
|
Fix mailslot name when no export list is specified.
|
|
AddToMsg's caller should get a shared lock on master list.
|
|
InitMsgBuf() should get a shared lock on config data.
|
|
22-Feb-1992 JohnRo
|
|
Minor changes to mailslot name handling.
|
|
24-Mar-1992 JohnRo
|
|
Renamed many ReplGlobal vars to ReplConfig vars.
|
|
Clarify value of pulse_rate field.
|
|
Added more debug output.
|
|
Make sure some things are aligned.
|
|
27-Mar-1992 JohnRo
|
|
Some UNICODE strings in packet should be unaligned.
|
|
25-Oct-1992 jimkel
|
|
rename RMGlobalClient* to RMGlobalImport*
|
|
now locked by ReplConfigLock
|
|
15-Feb-1993 JohnRo
|
|
RAID 11365: Fixed various mailslot size problems.
|
|
Corrected some message format comments.
|
|
Use NetpKdPrint() where possible.
|
|
Made changes suggested by PC-LINT 5.0
|
|
Use PREFIX_ equates.
|
|
|
|
--*/
|
|
|
|
|
|
// These must be included first:
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <lmcons.h>
|
|
|
|
// These may be included in any order:
|
|
|
|
#include <lmerrlog.h>
|
|
#include <alertmsg.h>
|
|
#include <netdebug.h> // DBGSTATIC, NetDbgHexDump(), FORMAT_ equates, etc.
|
|
#include <prefix.h> // PREFIX_ equates.
|
|
#include <smbgtpt.h>
|
|
#include <netlib.h>
|
|
#include <netlock.h> // ACQUIRE_LOCK_SHARED(), etc.
|
|
#include <string.h> // strcpy(), strlen().
|
|
#include <tstring.h> // NetpAlloc{type}From{type}(), etc.
|
|
#include <stdlib.h> // wcscpy(), etc.
|
|
|
|
|
|
// repl headers
|
|
|
|
#include <repldefs.h> // IF_DEBUG(), etc.
|
|
#include <replgbl.h> // ReplGlobal and ReplConfig variables.
|
|
#include <replpack.h>
|
|
#include <master.h>
|
|
#include <replp.h>
|
|
|
|
/*++
|
|
|
|
DATA STRUCTURES:
|
|
|
|
1. MsgBuf[max mailsot message size] - used for actual send - WriteMailsot.
|
|
|
|
This buffer is formatted as follows:
|
|
|
|
In compatibility mode: (will hold ANSI and UNICODE strings)
|
|
|
|
Fixed part:
|
|
|
|
1. MSG_HEADER header;
|
|
|
|
WORD msg_type;
|
|
CHAR sender[CNLEN+1];
|
|
CHAR senders_domain[DNLEN+1];
|
|
|
|
2. REPL_INFO info;
|
|
|
|
WORD random;
|
|
WORD sync_rate;
|
|
WORD pulse_rate; (pulse time * sync rate)
|
|
WORD guard_time;
|
|
|
|
3. WORD update_count;
|
|
|
|
4. MSG_STATUS_REC - update_count records
|
|
|
|
WORD dir_name_offset;
|
|
WORD opcode;
|
|
DWORD checksum; (old style checksum)
|
|
WORD count;
|
|
WORD integrity;
|
|
WORD extent;
|
|
|
|
5. UNICODE_ANSI_MSG_HEADER
|
|
|
|
WCHAR sender[CNLEN+1]; (or shorter; unaligned)
|
|
WCHAR senders_domain[DNLEN+1]; (or shorter; unaligned)
|
|
|
|
Variable Part:
|
|
|
|
6. DIR_NAMEs - update_count name pairs
|
|
|
|
CHAR AnsiDirName[PATHLEN+1]; (or shorter)
|
|
WCHAR UnicodeDirName[PATHLEN+1]; (or shorter; unaligned)
|
|
|
|
7. NT MESSAGE SIGNATURE
|
|
|
|
DWORD Signature (unaligned)
|
|
|
|
In NT only mode: (with UNICODE strings only)
|
|
|
|
1. UNICODE_MSG_HEADER header;
|
|
|
|
WORD msg_type;
|
|
CHAR sender[CNLEN+1]; // NULL string
|
|
CHAR senders_domain[DNLEN+1]; // NULL string
|
|
|
|
2. REPL_INFO info;
|
|
|
|
WORD random;
|
|
WORD sync_rate;
|
|
WORD pulse_rate; (pulse time * sync rate)
|
|
WORD guard_time;
|
|
|
|
3. WORD update_count;
|
|
|
|
4. MSG_STATUS_REC - update count records
|
|
|
|
WORD dir_name_offset;
|
|
WORD opcode;
|
|
DWORD checksum;
|
|
WORD count;
|
|
WORD integrity;
|
|
WORD extent;
|
|
|
|
5. UNICODE_ANSI_MSG_HEADER
|
|
|
|
WCHAR sender[CNLEN+1];
|
|
WCHAR senders_domain[DNLEN+1];
|
|
|
|
Variable Part:
|
|
|
|
6. DIR_NAMEs - update_count name pairs
|
|
|
|
CHAR Null String;
|
|
WCHAR UnicodeDirName;
|
|
|
|
7. NT MESSAGE SIGNATURE
|
|
|
|
DWORD Signature
|
|
|
|
2. UpdateList: list of update records.
|
|
|
|
UpdateList sentinel will have the following fields:
|
|
|
|
1. count of update records in the list.
|
|
|
|
2. Pointer to head of the list.
|
|
|
|
3. Pointer to tail of the list.
|
|
|
|
Each entry in the list will have the following fields.
|
|
|
|
1. Pointer to next record.
|
|
|
|
2. Pointer to prev record.
|
|
|
|
3. STATUS_REC structure.
|
|
|
|
3. FreeList: list of free record space.
|
|
|
|
Initially the list will be empty list, as update records come in
|
|
we will allote record space and when update records are freed, the
|
|
free record space is saved in this list. However this free list will
|
|
save only maximum of MAX_FREE_RECORDS.
|
|
|
|
FUNCTIONS:
|
|
|
|
1. InitMsgBuf()
|
|
|
|
- initializes MsgBuf with MSG_HEADER and REPL_INFO,
|
|
and UpdateList to NULL list.
|
|
|
|
2. InitMsgSend(type)
|
|
|
|
- Plugs msg_type in header and reset UpdateList.
|
|
|
|
3. AddToMsg(upd_rec)
|
|
|
|
- adds upd_rec to upd_buf to UpdateList.
|
|
|
|
4. MsgSend()
|
|
|
|
- Sends the message. uses as many mailslot writes as
|
|
needed to send the entire UpdateList.
|
|
|
|
--*/
|
|
|
|
#define MAX_FREE_RECORDS 10
|
|
|
|
#define NO_SAVE 0
|
|
#define SAVE 1
|
|
|
|
// type defs
|
|
|
|
struct update_rec {
|
|
struct update_rec *NextRec;
|
|
struct update_rec *PrevRec;
|
|
STATUS_REC UpdateEntry;
|
|
};
|
|
|
|
typedef struct update_rec UPDATE_REC;
|
|
typedef struct update_rec * PUPDATE_REC;
|
|
//typedef struct update_rec * LPUPDATE_REC;
|
|
|
|
struct list_sentinel {
|
|
DWORD count;
|
|
PUPDATE_REC Head;
|
|
PUPDATE_REC Tail;
|
|
};
|
|
|
|
typedef struct list_sentinel LIST_SENTINEL;
|
|
|
|
// G L O B A L S:
|
|
|
|
DBGSTATIC LIST_SENTINEL UpdateList; // update list header
|
|
|
|
DBGSTATIC LIST_SENTINEL FreeList; // free list header
|
|
// Note: FreeList is a singly linked list. so FreeList.tail field and
|
|
// the PrevRec field in FreeRecs are unused.
|
|
|
|
|
|
DBGSTATIC CHAR MsgBuf[MAX_2_MSLOT_SIZE];
|
|
|
|
DBGSTATIC VOID
|
|
SendToAll(
|
|
IN LPBYTE MsgBuffer,
|
|
IN DWORD MsgSize
|
|
);
|
|
|
|
DBGSTATIC VOID
|
|
AddUpdateRec(
|
|
IN OUT PUPDATE_REC UpdateRec
|
|
);
|
|
|
|
DBGSTATIC VOID
|
|
DeleteUpdateRec(
|
|
IN PUPDATE_REC UpdateRec
|
|
);
|
|
|
|
DBGSTATIC PUPDATE_REC
|
|
GetFreeUpdateRec(
|
|
VOID
|
|
);
|
|
|
|
DBGSTATIC VOID
|
|
FreeUpdateRec(
|
|
IN PUPDATE_REC UpdateRec,
|
|
IN DWORD SaveFlag
|
|
);
|
|
|
|
DBGSTATIC VOID
|
|
FreeUpdateList(
|
|
IN DWORD SaveFlag
|
|
);
|
|
|
|
DBGSTATIC VOID
|
|
FreeFreeList(
|
|
VOID
|
|
);
|
|
|
|
DBGSTATIC DWORD
|
|
GetNumRecFitIn(
|
|
IN DWORD BufSize,
|
|
OUT LPDWORD FitSize
|
|
);
|
|
|
|
|
|
BOOL
|
|
InitMsgBuf(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by InitMsg ( called at Master start ).
|
|
Initializes MsgBuf and UpdateList;
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE iff no error occurred.
|
|
|
|
Threads:
|
|
|
|
Only called by pulser thread.
|
|
|
|
--*/
|
|
{
|
|
PPACK_SYNCMSG SyncMsg;
|
|
|
|
//
|
|
// initialize UpdateList
|
|
//
|
|
|
|
UpdateList.Head = UpdateList.Tail = NULL;
|
|
UpdateList.count = 0;
|
|
|
|
//
|
|
// initialize FreeList
|
|
//
|
|
|
|
FreeList.Head = FreeList.Tail = NULL;
|
|
FreeList.count = 0;
|
|
|
|
//
|
|
// initialize MsgBuf.
|
|
//
|
|
|
|
SyncMsg = (PPACK_SYNCMSG)MsgBuf;
|
|
|
|
if( RMGlobalCompatibilityMode ) {
|
|
|
|
// copy Ansi names in compatibility mode messaging
|
|
|
|
(void) strcpy( SyncMsg->header.sender,
|
|
ReplGlobalAnsiComputerName);
|
|
|
|
} else {
|
|
|
|
// insert NULL string
|
|
|
|
SyncMsg->header.sender[0] = '\0';
|
|
|
|
}
|
|
|
|
if( RMGlobalCompatibilityMode ) {
|
|
|
|
(void) strcpy( SyncMsg->header.senders_domain,
|
|
ReplGlobalAnsiDomainName);
|
|
|
|
} else {
|
|
|
|
// insert NULL string
|
|
|
|
SyncMsg->header.senders_domain[0] = '\0';
|
|
|
|
}
|
|
|
|
// copy other header info.
|
|
|
|
ACQUIRE_LOCK_SHARED( ReplConfigLock );
|
|
|
|
NetpAssert( ReplIsRandomValid( ReplConfigRandom ) );
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->info.random) ),
|
|
(WORD) ReplConfigRandom);
|
|
|
|
NetpAssert( ReplIsIntervalValid( ReplConfigInterval ) );
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->info.sync_rate) ),
|
|
(WORD) ReplConfigInterval);
|
|
|
|
NetpAssert( ReplIsPulseValid( ReplConfigPulse ) );
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->info.pulse_rate) ),
|
|
(WORD) (ReplConfigPulse * ReplConfigInterval));
|
|
|
|
NetpAssert( ReplIsGuardTimeValid( ReplConfigGuardTime ) );
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->info.guard_time) ),
|
|
(WORD) ReplConfigGuardTime);
|
|
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->update_count) ), 0);
|
|
|
|
RELEASE_LOCK( ReplConfigLock );
|
|
|
|
return TRUE;
|
|
|
|
} // end of InitMsgBuf
|
|
|
|
|
|
VOID
|
|
InitMsgSend(
|
|
IN DWORD msg_type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Plugs msg_type into MsgBuf, and initialize UpdateList;
|
|
|
|
Arguments:
|
|
msg_type: SYNC / GUARD / PULSE.
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// set message type in buffer
|
|
//
|
|
|
|
SmbPutUshort( (LPWORD)MsgBuf, (WORD) msg_type);
|
|
|
|
//
|
|
// initialize UpdateList
|
|
//
|
|
|
|
if(UpdateList.count != 0) {
|
|
|
|
FreeUpdateList(SAVE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
ReplMasterFreeMsgBuf(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
free update buffers. called from pulser thread main routine
|
|
|
|
Arguments:
|
|
none
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Free update records.
|
|
//
|
|
|
|
if(UpdateList.count != 0) {
|
|
|
|
FreeUpdateList(NO_SAVE);
|
|
|
|
}
|
|
|
|
//
|
|
// Free FreeList record memory
|
|
//
|
|
|
|
if(FreeList.count != 0) {
|
|
|
|
FreeFreeList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
AddToMsg(
|
|
IN PMASTER_LIST_REC rec,
|
|
IN DWORD opcode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add Update record to UpdateList.
|
|
|
|
Arguments:
|
|
|
|
rec - points to master_list_rec which holds dir name and status
|
|
variables. AddToMsg() assumes that the caller has at least a
|
|
read-only lock on this.
|
|
|
|
opcode - START / UPDATE / END / PULSE.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PUPDATE_REC UpdateRec;
|
|
|
|
|
|
UpdateRec = GetFreeUpdateRec();
|
|
|
|
if( UpdateRec == NULL ) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"ERROR_NOT_ENOUGH_MEMORY error in AddToMsg Function.\n" ));
|
|
|
|
// BUGBUG: Log this?
|
|
return;
|
|
|
|
}
|
|
|
|
UpdateRec->NextRec = NULL;
|
|
UpdateRec->PrevRec = NULL;
|
|
|
|
UpdateRec->UpdateEntry.opcode = opcode;
|
|
UpdateRec->UpdateEntry.checksum = rec->checksum;
|
|
UpdateRec->UpdateEntry.count = rec->count;
|
|
UpdateRec->UpdateEntry.integrity = rec->integrity;
|
|
UpdateRec->UpdateEntry.extent = rec->extent;
|
|
|
|
(void) STRCPY(UpdateRec->UpdateEntry.dir_name, rec->dir_name);
|
|
|
|
|
|
IF_DEBUG(PULSER) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"AddToMsg() is calling AddUpdateRec() "
|
|
"to add record for dir: " FORMAT_LPTSTR "\n", rec->dir_name ));
|
|
|
|
}
|
|
|
|
AddUpdateRec( UpdateRec );
|
|
NetpAssert( UpdateList.count > 0 );
|
|
|
|
} // end of AddToMsg
|
|
|
|
|
|
VOID
|
|
MsgSend(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends all update info in UpdateList to clients, via second class mail slot
|
|
to clients. Since slot size is limited (440 - sizeof(mailslot_name)),
|
|
must use multiple messages.
|
|
|
|
REQUIRES
|
|
|
|
1. MAX_2_MSLOT_SIZE defines effective max msg size.
|
|
2. UpdateList has data organized as described above.
|
|
3. MsgBuf has header info initialized by InitMsgBuf.
|
|
|
|
ENSURES:
|
|
|
|
1. All data is sent in (multiple) second class mailslot messages.
|
|
|
|
MODIFIES: None.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Threads:
|
|
|
|
Only called by pulser thread.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
DWORD NumRecs, FitSize;
|
|
PUPDATE_REC UpdateRec;
|
|
PUPDATE_REC NextRec;
|
|
PPACK_SYNCMSG SyncMsg;
|
|
LPBYTE Where;
|
|
DWORD Len;
|
|
|
|
|
|
PPACK_MSG_STATUS_REC StartMsgRec;
|
|
PPACK_MSG_STATUS_REC MsgRec;
|
|
|
|
IF_DEBUG( PULSER ) {
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"MsgSend: initial count is " FORMAT_DWORD ".\n",
|
|
UpdateList.count ));
|
|
}
|
|
|
|
while(UpdateList.count != 0) {
|
|
|
|
// determine the number of records that can fit in the MsgBuf
|
|
|
|
NumRecs = GetNumRecFitIn( sizeof(MsgBuf) , &FitSize);
|
|
NetpAssert( FitSize <= sizeof(MsgBuf) );
|
|
NetpAssert( FitSize <= MAX_2_MSLOT_SIZE );
|
|
if (NumRecs > 0) {
|
|
NetpAssert( FitSize > 0 );
|
|
}
|
|
|
|
|
|
SyncMsg = (PPACK_SYNCMSG) MsgBuf;
|
|
|
|
SmbPutUshort( (LPWORD) ( &(SyncMsg->update_count) ), (WORD) NumRecs);
|
|
|
|
StartMsgRec = (PPACK_MSG_STATUS_REC)
|
|
(MsgBuf + sizeof(PACK_SYNCMSG));
|
|
|
|
// copy fixed portion of status recs.
|
|
|
|
for(i = 0, MsgRec = StartMsgRec, UpdateRec = UpdateList.Head;
|
|
( i < NumRecs );
|
|
i++, MsgRec++, UpdateRec = UpdateRec->NextRec ) {
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->dir_name_offset) ), 0 );
|
|
// offset field set to zero initially
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->opcode) ),
|
|
(WORD) UpdateRec->UpdateEntry.opcode );
|
|
|
|
SmbPutUlong( (LPDWORD) ( &(MsgRec->checksum) ),
|
|
UpdateRec->UpdateEntry.checksum );
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->count) ),
|
|
(WORD) UpdateRec->UpdateEntry.count );
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->integrity) ),
|
|
(WORD) UpdateRec->UpdateEntry.integrity );
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->extent) ),
|
|
(WORD) UpdateRec->UpdateEntry.extent );
|
|
|
|
}
|
|
|
|
Where = (LPBYTE)( StartMsgRec + NumRecs );
|
|
|
|
// copy Unicode sender name
|
|
|
|
Len = ( wcslen( ReplGlobalUnicodeComputerName ) + 1) * sizeof(WCHAR);
|
|
|
|
NetpMoveMemory(Where, (LPBYTE) ReplGlobalUnicodeComputerName, Len);
|
|
|
|
Where += Len;
|
|
|
|
// copy Unicode domain name.
|
|
|
|
Len = ( wcslen( ReplGlobalUnicodeDomainName ) + 1) * sizeof(WCHAR);
|
|
|
|
NetpMoveMemory(Where, (LPBYTE) ReplGlobalUnicodeDomainName, Len);
|
|
|
|
Where += Len;
|
|
|
|
// copy variables portions ..
|
|
|
|
for(i = 0, MsgRec = StartMsgRec, UpdateRec = UpdateList.Head;
|
|
( i < NumRecs );
|
|
i++, MsgRec++, UpdateRec = UpdateRec->NextRec ) {
|
|
|
|
SmbPutUshort( (LPWORD) ( &(MsgRec->dir_name_offset) ),
|
|
(WORD) ( (LPBYTE)Where - (LPBYTE)MsgBuf) );
|
|
|
|
if( RMGlobalCompatibilityMode ) {
|
|
|
|
#if defined(DBCS) && defined(UNICODE) // MsgSend()
|
|
NetpCopyWStrToStrDBCS(
|
|
Where, // dest
|
|
UpdateRec->UpdateEntry.dir_name ); // src
|
|
#else
|
|
NetpCopyTStrToStr(
|
|
Where, // dest
|
|
UpdateRec->UpdateEntry.dir_name ); // src
|
|
#endif // defined(DBCS)
|
|
|
|
Len = strlen( (LPSTR) Where) + 1;
|
|
|
|
Where += Len;
|
|
|
|
} else {
|
|
|
|
*(PCHAR)Where = '\0';
|
|
|
|
Where += sizeof(CHAR);
|
|
}
|
|
|
|
// copy Unicode name
|
|
|
|
Len = ( STRLEN( UpdateRec->UpdateEntry.dir_name ) + 1 ) *
|
|
sizeof(WCHAR);
|
|
|
|
NetpCopyTStrToUnalignedWStr(
|
|
Where, // dest
|
|
UpdateRec->UpdateEntry.dir_name ); // src
|
|
|
|
Where += Len;
|
|
|
|
}
|
|
|
|
// add NT message token at the end ..
|
|
|
|
SmbPutUlong( (LPDWORD)Where, NT_MSG_TOKEN );
|
|
|
|
SendToAll((LPBYTE)MsgBuf, FitSize);
|
|
|
|
|
|
IF_DEBUG(PULSER) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"MsgSend() sent the following "
|
|
FORMAT_DWORD " record(s):\n", NumRecs ));
|
|
|
|
}
|
|
|
|
// delete Update records
|
|
for(i = 0, UpdateRec = UpdateList.Head;
|
|
( i < NumRecs ) && ( UpdateRec != NULL );
|
|
i++, UpdateRec = NextRec ) {
|
|
|
|
IF_DEBUG(PULSER) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
" " FORMAT_LPTSTR "\n",
|
|
UpdateRec->UpdateEntry.dir_name ));
|
|
|
|
}
|
|
|
|
NextRec = UpdateRec->NextRec;
|
|
DeleteUpdateRec(UpdateRec);
|
|
|
|
}
|
|
}
|
|
|
|
} // end MsgSend
|
|
|
|
|
|
DBGSTATIC VOID
|
|
SendToAll(
|
|
IN LPBYTE MsgBuffer,
|
|
IN DWORD MsgSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends message to all clients listed in client_list.
|
|
|
|
ENTRY: pointer to message buffer.
|
|
|
|
REQUIRES:
|
|
1. MsgBuf has all header entries filled in.
|
|
2. RMGlobalImportList has RMGlobalImportCount valid entries.
|
|
|
|
ENSURES: 1. Message sent all clients in client list.
|
|
|
|
MODIFIES: None.
|
|
|
|
Arguments:
|
|
|
|
msgp - pointer to message buffer
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Threads:
|
|
|
|
Only called by pulser thread.
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS ApiStatus;
|
|
TCHAR destin[FULL_SLOT_NAME_SIZE];
|
|
DWORD i;
|
|
|
|
NetpAssert( MsgBuffer != NULL );
|
|
NetpAssert( MsgSize != 0 );
|
|
|
|
IF_DEBUG( PULSER ) {
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"(Pulser) outgoing message follows:\n" ));
|
|
NetpDbgHexDump( MsgBuffer, MsgSize );
|
|
}
|
|
|
|
ACQUIRE_LOCK_SHARED( ReplConfigLock ); // get read-only lock here.
|
|
|
|
//
|
|
// stick in leading double slashes for computer name.
|
|
//
|
|
|
|
|
|
if (RMGlobalImportCount != 0) {
|
|
|
|
for (i = 0; i < RMGlobalImportCount; i++) {
|
|
|
|
NetpAssert( RMGlobalImportList[i] != NULL );
|
|
NetpAssert( (*(RMGlobalImportList[i])) != TCHAR_EOS );
|
|
|
|
(void) STRCPY(destin, SLASH_SLASH);
|
|
(void) STRCAT(destin, RMGlobalImportList[i]);
|
|
(void) STRCAT(destin, (LPTSTR) CLIENT_SLOT_NAME);
|
|
|
|
ApiStatus = NetpReplWriteMail(destin, MsgBuffer, MsgSize);
|
|
if (ApiStatus != NO_ERROR) {
|
|
|
|
NetpAssert( ApiStatus != ERROR_INVALID_FUNCTION );
|
|
|
|
AlertLogExit(ALERT_ReplSysErr,
|
|
NELOG_ReplNetErr,
|
|
ApiStatus,
|
|
NULL,
|
|
NULL,
|
|
NO_EXIT);
|
|
|
|
// Don't forget to release lock...
|
|
}
|
|
|
|
IF_DEBUG(PULSER) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"SendToall() sent a mailslot message of size "
|
|
FORMAT_DWORD " to " FORMAT_LPTSTR " successfully.\n",
|
|
MsgSize, destin ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // RMGlobalImportCount == 0 - send to domain name
|
|
|
|
NetpAssert( ReplGlobalDomainName != NULL );
|
|
NetpAssert( (*ReplGlobalDomainName) != TCHAR_EOS );
|
|
|
|
(void) STRCPY(destin, SLASH_SLASH);
|
|
(void) STRCAT(destin, ReplGlobalDomainName);
|
|
(void) STRCAT(destin, (LPTSTR) CLIENT_SLOT_NAME);
|
|
|
|
ApiStatus = NetpReplWriteMail(destin, MsgBuffer, MsgSize);
|
|
if (ApiStatus != NO_ERROR) {
|
|
NetpAssert( ApiStatus != ERROR_INVALID_FUNCTION );
|
|
AlertLogExit(ALERT_ReplSysErr,
|
|
NELOG_ReplNetErr,
|
|
ApiStatus,
|
|
NULL,
|
|
NULL,
|
|
NO_EXIT);
|
|
|
|
// Don't forget to release lock...
|
|
|
|
}
|
|
|
|
IF_DEBUG(PULSER) {
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"SendToall() sent a mailslot message of size " FORMAT_DWORD
|
|
" to " FORMAT_LPTSTR " successfully.\n",
|
|
MsgSize, destin ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RELEASE_LOCK( ReplConfigLock );
|
|
|
|
}
|
|
|
|
DBGSTATIC VOID
|
|
AddUpdateRec(
|
|
IN OUT PUPDATE_REC UpdateRec
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a update record to UpdateList.
|
|
|
|
Arguments:
|
|
|
|
UpdateRec - pointer to new update rec.
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
ASSUME:
|
|
|
|
NextRec and PrevRec fields are initialized to NULL before
|
|
calling this function.
|
|
|
|
--*/
|
|
{
|
|
|
|
// special case, if list is empty
|
|
if( UpdateList.count == 0) {
|
|
|
|
// add new record
|
|
|
|
UpdateList.Head = UpdateRec;
|
|
UpdateList.Tail = UpdateRec;
|
|
|
|
// set counter
|
|
|
|
UpdateList.count = 1;
|
|
|
|
} else {
|
|
|
|
// add new record to end of list
|
|
|
|
// adjust new record pointer
|
|
|
|
UpdateRec->PrevRec = UpdateList.Tail;
|
|
|
|
// adjust tail record pointer
|
|
|
|
UpdateList.Tail->NextRec = UpdateRec;
|
|
|
|
// adjust UpdateList rec pointer
|
|
|
|
UpdateList.Tail = UpdateRec;
|
|
|
|
// adjust counter
|
|
|
|
UpdateList.count++;
|
|
}
|
|
|
|
NetpAssert( UpdateList.count > 0 );
|
|
}
|
|
|
|
DBGSTATIC VOID
|
|
DeleteUpdateRec(
|
|
IN PUPDATE_REC UpdateRec
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete a record from UpdateList
|
|
|
|
Arguments:
|
|
|
|
UpdateRec - pointer to the record to be removed from list
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
ASSUME: the given record is assumed to be in the UpdateList.
|
|
|
|
--*/
|
|
{
|
|
// handle special cases first
|
|
|
|
if( ( UpdateRec->NextRec == NULL ) &&
|
|
( UpdateRec->PrevRec == NULL ) ) {
|
|
|
|
// last record removed from the list
|
|
|
|
if( UpdateList.count != 1 ) {
|
|
|
|
// assertion failed
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"Assertion failed in DeleteUpdateRec function, "
|
|
"expected update list count 1, it is "
|
|
FORMAT_HEX_DWORD ".\n", UpdateList.count ));
|
|
|
|
return;
|
|
}
|
|
|
|
if( ( UpdateList.Head != UpdateRec ) ||
|
|
( UpdateList.Tail != UpdateRec ) ) {
|
|
|
|
// assertion failed
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"Assertion failed in DeleteUpdateRec function, "
|
|
"bogus UpdateRec pointer.\n" ));
|
|
|
|
return;
|
|
}
|
|
|
|
// adjust pointers
|
|
|
|
UpdateList.Head = NULL;
|
|
UpdateList.Tail = NULL;
|
|
UpdateList.count = 0;
|
|
|
|
// free update record
|
|
FreeUpdateRec( UpdateRec, SAVE );
|
|
|
|
return;
|
|
}
|
|
|
|
if( UpdateRec->NextRec == NULL ) {
|
|
|
|
// record removed from tail
|
|
|
|
if( ( UpdateList.Tail != UpdateRec ) ) {
|
|
|
|
// assertion failed
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"Assertion failed in DeleteUpdateRec function, "
|
|
"bogus UpdateRec pointer.\n" ));
|
|
|
|
return;
|
|
}
|
|
|
|
// adjust pointers
|
|
|
|
UpdateList.Tail = UpdateRec->PrevRec;
|
|
UpdateRec->PrevRec->NextRec = NULL;
|
|
UpdateList.count--;
|
|
|
|
// free update record
|
|
FreeUpdateRec( UpdateRec, SAVE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( UpdateRec->PrevRec == NULL ) {
|
|
|
|
// record removed from head
|
|
|
|
if( ( UpdateList.Head != UpdateRec ) ) {
|
|
|
|
// assertion failed
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"Assertion failed in DeleteUpdateRec function, "
|
|
"bogus UpdateRec pointer.\n" ));
|
|
|
|
return;
|
|
}
|
|
|
|
// set UpdateList sentinel
|
|
|
|
UpdateList.Head = UpdateRec->NextRec;
|
|
UpdateRec->NextRec->PrevRec = NULL;
|
|
UpdateList.count--;
|
|
|
|
// free update record
|
|
FreeUpdateRec( UpdateRec, SAVE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// record removed from middle
|
|
|
|
if( ( UpdateRec->NextRec->PrevRec != UpdateRec ) ||
|
|
( UpdateRec->PrevRec->NextRec != UpdateRec ) ) {
|
|
|
|
// assertion failed
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"Assertion failed in DeleteUpdateRec function, "
|
|
"bogus UpdateRec pointer.\n" ));
|
|
|
|
return;
|
|
}
|
|
|
|
UpdateRec->NextRec->PrevRec = UpdateRec->PrevRec;
|
|
UpdateRec->PrevRec->NextRec = UpdateRec->NextRec;
|
|
|
|
UpdateList.count--;
|
|
|
|
// free update record
|
|
FreeUpdateRec( UpdateRec, SAVE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DBGSTATIC PUPDATE_REC
|
|
GetFreeUpdateRec(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get a free update rec buffer either from free list or allocate new memory.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
|
|
Return Value:
|
|
|
|
return a pointer to new update record, or NULL if out of memory.
|
|
|
|
Note - FreeList is a singlely linked list. so FreeList.Tail field and
|
|
the PrevRec field in FreeRecs are unused.
|
|
|
|
--*/
|
|
{
|
|
PUPDATE_REC FreeRecord;
|
|
|
|
if( FreeList.count > 0 ) {
|
|
|
|
// get a record from free list
|
|
|
|
FreeRecord = FreeList.Head;
|
|
NetpAssert( FreeRecord != NULL );
|
|
|
|
FreeList.Head = FreeRecord->NextRec;
|
|
|
|
FreeList.count--;
|
|
|
|
return FreeRecord;
|
|
}
|
|
|
|
// allote new block of memory
|
|
|
|
FreeRecord = (PUPDATE_REC) NetpMemoryAllocate( sizeof(UPDATE_REC) );
|
|
|
|
return FreeRecord;
|
|
|
|
}
|
|
|
|
DBGSTATIC VOID
|
|
FreeUpdateRec(
|
|
IN PUPDATE_REC UpdateRec,
|
|
IN DWORD SaveFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an update record, this record will either be put in FreeList or
|
|
the memory is freed back to system.
|
|
|
|
Arguments:
|
|
|
|
UpdateRec - pointer to the record that should be freed
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Note - FreeList is a singlely linked list. so FreeList.tail field and
|
|
the PrevRec field in FreeRecs are unused.
|
|
|
|
--*/
|
|
{
|
|
if( (SaveFlag == NO_SAVE) || ( FreeList.count >= MAX_FREE_RECORDS ) ) {
|
|
|
|
// free this update record block memory to system.
|
|
|
|
NetpMemoryFree(UpdateRec);
|
|
|
|
return;
|
|
}
|
|
|
|
// add this block to free list
|
|
|
|
UpdateRec->NextRec = FreeList.Head;
|
|
UpdateRec->PrevRec = NULL; // unused
|
|
FreeList.Head = UpdateRec;
|
|
|
|
FreeList.count++;
|
|
|
|
return;
|
|
}
|
|
|
|
DBGSTATIC VOID
|
|
FreeUpdateList(
|
|
IN DWORD SaveFlag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free up the all update records from UpdateList
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
|
|
PUPDATE_REC UpdateRec, NextRec;
|
|
|
|
UpdateRec = UpdateList.Head;
|
|
|
|
while(UpdateRec != NULL) {
|
|
|
|
NextRec = UpdateRec->NextRec;
|
|
|
|
FreeUpdateRec( UpdateRec, SaveFlag );
|
|
|
|
UpdateRec = NextRec;
|
|
}
|
|
|
|
UpdateList.Head = NULL;
|
|
UpdateList.Tail = NULL;
|
|
UpdateList.count = 0;
|
|
|
|
}
|
|
|
|
|
|
DBGSTATIC VOID
|
|
FreeFreeList(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free up the memory blocks in FreeList.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Note - FreeList is a singlely linked list. so FreeList.tail field and
|
|
the PrevRec field in FreeRecs are unused.
|
|
|
|
--*/
|
|
{
|
|
|
|
PUPDATE_REC FreeRec, NextRec;
|
|
|
|
FreeRec = FreeList.Head;
|
|
|
|
while( FreeRec != NULL ) {
|
|
|
|
NextRec = FreeRec->NextRec;
|
|
|
|
NetpMemoryFree( FreeRec );
|
|
|
|
FreeRec = NextRec;
|
|
}
|
|
|
|
FreeList.Head = NULL;
|
|
FreeList.Tail = NULL;
|
|
FreeList.count = 0;
|
|
|
|
}
|
|
|
|
DBGSTATIC DWORD
|
|
GetNumRecFitIn(
|
|
IN DWORD BufSize,
|
|
OUT LPDWORD FitSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute the number of update records that will fit in the buffer. If there
|
|
are fewer update records in UpdateList than the number of records that the
|
|
buffer will fit in, it will return that count.
|
|
|
|
Arguments:
|
|
|
|
BufSize - buffer size
|
|
|
|
FitSize - the exact size of the buffer required to fill in number records
|
|
that is returned.
|
|
|
|
Return Value:
|
|
|
|
return number of records that can be filled in the buffer.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD LocalFitSize;
|
|
DWORD NumMsgs;
|
|
PUPDATE_REC UpdateRec;
|
|
DWORD NextRecSize;
|
|
|
|
NetpAssert( BufSize <= MAX_2_MSLOT_SIZE );
|
|
|
|
// space required for header portion of data
|
|
|
|
LocalFitSize = sizeof(PACK_SYNCMSG) +
|
|
( wcslen( ReplGlobalUnicodeComputerName ) + 1 +
|
|
wcslen( ReplGlobalUnicodeDomainName ) + 1
|
|
) * sizeof(WCHAR) +
|
|
sizeof(NT_MSG_TOKEN);
|
|
|
|
if( BufSize < LocalFitSize ) {
|
|
|
|
// insufficient buffer size
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
" Insufficient message buffer size " FORMAT_DWORD ".\n",
|
|
BufSize ));
|
|
|
|
*FitSize = 0;
|
|
|
|
return ( 0 );
|
|
}
|
|
|
|
UpdateRec = UpdateList.Head;
|
|
|
|
NumMsgs = 0;
|
|
|
|
while( UpdateRec != NULL ) {
|
|
|
|
// Fixed portion + variable portion.
|
|
// ( Unicode string + Ansi string )
|
|
|
|
NextRecSize = ( sizeof(PACK_MSG_STATUS_REC) ) +
|
|
( ( STRLEN(UpdateRec->UpdateEntry.dir_name) + 1 ) *
|
|
(sizeof(WCHAR) + sizeof(CHAR) ) );
|
|
|
|
if( BufSize < ( LocalFitSize + NextRecSize ) ) {
|
|
|
|
if( NumMsgs == 0) {
|
|
|
|
// insufficient buffer size
|
|
|
|
NetpKdPrint(( PREFIX_REPL_MASTER
|
|
"GetNumRecFitIn: "
|
|
"Insufficient message buffer size " FORMAT_DWORD
|
|
" for single update \n",
|
|
BufSize ));
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
LocalFitSize += NextRecSize;
|
|
|
|
NumMsgs++;
|
|
|
|
UpdateRec = UpdateRec->NextRec;
|
|
}
|
|
|
|
*FitSize = LocalFitSize;
|
|
|
|
return ( NumMsgs );
|
|
|
|
}
|