|
|
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name: frscomm.c
Abstract: Routines for the comm layer to convert to and from communication packets.
Author: Billy J. Fuller 29-May-1997
David Orbits 21-Mar-2000 Restructured to use table and provide extensible elements.
Environment User mode winnt
--*/
#include <ntreppch.h>
#pragma hdrstop
#include <frs.h>
extern PGEN_TABLE CompressionTable;
//
// Types for the common comm subsystem
//
// WARNING: The order of these entries can never change. This ensures that
// packets can be exchanged between uplevel and downlevel members.
//
typedef enum _COMMTYPE { COMM_NONE = 0,
COMM_BOP, // beginning of packet
COMM_COMMAND, // command packet stuff
COMM_TO, COMM_FROM, COMM_REPLICA, COMM_JOIN_GUID, COMM_VVECTOR, COMM_CXTION,
COMM_BLOCK, // file data
COMM_BLOCK_SIZE, COMM_FILE_SIZE, COMM_FILE_OFFSET,
COMM_REMOTE_CO, // remote change order command
COMM_GVSN, // version (guid, vsn)
COMM_CO_GUID, // change order guid
COMM_CO_SEQUENCE_NUMBER,// CO Seq number for ack.
COMM_JOIN_TIME, // machine's can't join if there times or badly out of sync
COMM_LAST_JOIN_TIME, // The Last time this connection was joined.
// Used to detect Database mismatch.
COMM_EOP, // end of packet
COMM_REPLICA_VERSION_GUID, // replica version guid (originator guid)
COMM_MD5_DIGEST, // md5 digest
//
// Change Order Record Extension. If not supplied the the ptr for
// what was Spare1Bin (now Extension) is left as Null. So comm packets
// sent from down level members still work.
//
COMM_CO_EXT_WIN2K, // in down level code this was called COMM_CO_EXTENSION.
//
// See comment in schema.h for why we need to seperate the var len
// COMM_CO_EXTENSION_2 from COMM_CO_EXT_WIN2K above.
//
COMM_CO_EXTENSION_2,
COMM_COMPRESSION_GUID, // Guid for a supported compression algorithm.
//
// WARNING: To ensure that down level members can read Comm packets
// from uplevel clients always add net data type codes here.
//
COMM_MAX } COMM_TYPE, *PCOMM_TYPE; #define COMM_NULL_DATA (-1)
//
// The decode data types are defined below. They are used in the CommPacketTable
// to aid in decode dispatching and comm packet construction
// They DO NOT get sent in the actual packet.
//
typedef enum _COMM_PACKET_DECODE_TYPE { COMM_DECODE_NONE = 0, COMM_DECODE_ULONG, COMM_DECODE_ULONG_TO_USHORT, COMM_DECODE_GNAME, COMM_DECODE_BLOB, COMM_DECODE_ULONGLONG, COMM_DECODE_VVECTOR, COMM_DECODE_VAR_LEN_BLOB, COMM_DECODE_REMOTE_CO, COMM_DECODE_GUID, COMM_DECODE_MAX } COMM_PACKET_DECODE_TYPE, *PCOMM_PACKET_DECODE_TYPE;
//
// The COMM_PACKET_ELEMENT struct is used in a table to describe the data
// elements in a Comm packet.
//
typedef struct _COMM_PACKET_ELEMENT_ { COMM_TYPE CommType; PCHAR CommTag; ULONG DataSize; ULONG DecodeType; ULONG NativeOffset; } COMM_PACKET_ELEMENT, *PCOMM_PACKET_ELEMENT;
#define COMM_MEM_SIZE (128)
//
// Size of the required Beginning-of-packet and End-of-Packet fields
//
#define MIN_COMM_PACKET_SIZE (2 * (sizeof(USHORT) + sizeof(ULONG) + sizeof(ULONG)))
#define COMM_SZ_UL sizeof(ULONG)
#define COMM_SZ_ULL sizeof(ULONGLONG)
#define COMM_SZ_GUID sizeof(GUID)
#define COMM_SZ_GUL sizeof(GUID) + sizeof(ULONG)
#define COMM_SZ_GVSN sizeof(GVSN) + sizeof(ULONG)
#define COMM_SZ_NULL 0
#define COMM_SZ_COC sizeof(CHANGE_ORDER_COMMAND) + sizeof(ULONG)
//#define COMM_SZ_COC CO_PART1_SIZE + CO_PART2_SIZE + CO_PART3_SIZE + sizeof(ULONG)
#define COMM_SZ_COEXT_W2K sizeof(CO_RECORD_EXTENSION_WIN2K) + sizeof(ULONG)
#define COMM_SZ_MD5 MD5DIGESTLEN + sizeof(ULONG)
#define COMM_SZ_JTIME sizeof(ULONGLONG) + sizeof(ULONG)
//
// Note: When using COMM_DECODE_VAR_LEN_BLOB you must also use COMM_SZ_NULL
// in the table below so that no length check is made when the field is decoded.
// This allows the field size to grow. Down level members must be able to
// handle this by ignoring var len field components they do not understand.
//
//
// The Communication packet element table below is used to construct and
// decode comm packet data sent between members.
// *** WARNING *** - the order of the rows in the table must match the
// the order of the elements in the COMM_TYPE enum. See comments for COMM_TYPE
// enum for restrictions on adding new elements to the table.
//
// Data Element Type DisplayText Size Decode Type Offset to Native Cmd Packet
//
COMM_PACKET_ELEMENT CommPacketTable[COMM_MAX] = { {COMM_NONE, "NONE" , COMM_SZ_NULL, COMM_DECODE_NONE, 0 },
{COMM_BOP, "BOP" , COMM_SZ_UL, COMM_DECODE_ULONG, RsOffsetSkip }, {COMM_COMMAND, "COMMAND" , COMM_SZ_UL, COMM_DECODE_ULONG_TO_USHORT, OFFSET(COMMAND_PACKET, Command)}, {COMM_TO, "TO" , COMM_SZ_NULL, COMM_DECODE_GNAME, RsOffset(To) }, {COMM_FROM, "FROM" , COMM_SZ_NULL, COMM_DECODE_GNAME, RsOffset(From) }, {COMM_REPLICA, "REPLICA" , COMM_SZ_NULL, COMM_DECODE_GNAME, RsOffset(ReplicaName) }, {COMM_JOIN_GUID, "JOIN_GUID" , COMM_SZ_GUL, COMM_DECODE_BLOB, RsOffset(JoinGuid) }, {COMM_VVECTOR, "VVECTOR" , COMM_SZ_GVSN, COMM_DECODE_VVECTOR, RsOffset(VVector) }, {COMM_CXTION, "CXTION" , COMM_SZ_NULL, COMM_DECODE_GNAME, RsOffset(Cxtion) },
{COMM_BLOCK, "BLOCK" , COMM_SZ_NULL, COMM_DECODE_BLOB, RsOffset(Block) }, {COMM_BLOCK_SIZE, "BLOCK_SIZE" , COMM_SZ_ULL, COMM_DECODE_ULONGLONG, RsOffset(BlockSize) }, {COMM_FILE_SIZE, "FILE_SIZE" , COMM_SZ_ULL, COMM_DECODE_ULONGLONG, RsOffset(FileSize) }, {COMM_FILE_OFFSET, "FILE_OFFSET" , COMM_SZ_ULL, COMM_DECODE_ULONGLONG, RsOffset(FileOffset) },
{COMM_REMOTE_CO, "REMOTE_CO" , COMM_SZ_COC, COMM_DECODE_REMOTE_CO, RsOffset(PartnerChangeOrderCommand)}, {COMM_GVSN, "GVSN" , COMM_SZ_GVSN, COMM_DECODE_BLOB, RsOffset(GVsn) },
{COMM_CO_GUID, "CO_GUID" , COMM_SZ_GUL, COMM_DECODE_BLOB, RsOffset(ChangeOrderGuid) }, {COMM_CO_SEQUENCE_NUMBER, "CO_SEQUENCE_NUMBER" , COMM_SZ_UL, COMM_DECODE_ULONG, RsOffset(ChangeOrderSequenceNumber)}, {COMM_JOIN_TIME, "JOIN_TIME" , COMM_SZ_JTIME, COMM_DECODE_BLOB, RsOffset(JoinTime) }, {COMM_LAST_JOIN_TIME, "LAST_JOIN_TIME" , COMM_SZ_ULL, COMM_DECODE_ULONGLONG, RsOffset(LastJoinTime) }, {COMM_EOP, "EOP" , COMM_SZ_UL, COMM_DECODE_ULONG, RsOffsetSkip }, {COMM_REPLICA_VERSION_GUID, "REPLICA_VERSION_GUID", COMM_SZ_GUL, COMM_DECODE_BLOB, RsOffset(ReplicaVersionGuid)}, {COMM_MD5_DIGEST, "MD5_DIGEST" , COMM_SZ_MD5, COMM_DECODE_BLOB, RsOffset(Md5Digest) }, {COMM_CO_EXT_WIN2K, "CO_EXT_WIN2K" , COMM_SZ_COEXT_W2K,COMM_DECODE_BLOB, RsOffset(PartnerChangeOrderCommandExt)}, {COMM_CO_EXTENSION_2, "CO_EXTENSION_2" , COMM_SZ_NULL, COMM_DECODE_VAR_LEN_BLOB, RsOffset(PartnerChangeOrderCommandExt)},
{COMM_COMPRESSION_GUID, "COMPRESSION_GUID" , COMM_SZ_GUID, COMM_DECODE_GUID, RsOffset(CompressionTable)}
};
VOID CommInitializeCommSubsystem( VOID ) /*++
Routine Description: Initialize the generic comm subsystem
Arguments: None.
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommInitializeCommSubsystem:"
//
// type must fit into a short
//
FRS_ASSERT(COMM_MAX <= 0xFFFF); }
VOID CommCopyMemory( IN PCOMM_PACKET CommPkt, IN PUCHAR Src, IN ULONG Len ) /*++
Routine Description: Copy memory into a comm packet, extending as necessary
Arguments: CommPkt Src Len
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommCopyMemory:"
ULONG MemLeft; PUCHAR NewPkt;
//
// Adjust size of comm packet if necessary
//
// PERF: How many allocs get done to send a CO??? This looks expensive.
MemLeft = CommPkt->MemLen - CommPkt->PktLen; if (Len > MemLeft) { //
// Just filling memory; extend memory, tacking on a little extra
//
CommPkt->MemLen = (((CommPkt->MemLen + Len) + (COMM_MEM_SIZE - 1)) / COMM_MEM_SIZE) * COMM_MEM_SIZE; NewPkt = FrsAlloc(CommPkt->MemLen); CopyMemory(NewPkt, CommPkt->Pkt, CommPkt->PktLen); FrsFree(CommPkt->Pkt); CommPkt->Pkt = NewPkt; }
//
// Copy into the packet
//
if (Src != NULL) { CopyMemory(CommPkt->Pkt + CommPkt->PktLen, Src, Len); } else { ZeroMemory(CommPkt->Pkt + CommPkt->PktLen, Len); } CommPkt->PktLen += Len; }
BOOL CommFetchMemory( IN PCOMM_PACKET CommPkt, IN PUCHAR Dst, IN ULONG Len ) /*++
Routine Description: Fetch memory from a comm packet, reading as necessary
Arguments: CommPkt Dst Len
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommFetchMemory:"
PUCHAR Src;
Src = CommPkt->Pkt + CommPkt->UpkLen; CommPkt->UpkLen += Len; if (CommPkt->UpkLen > CommPkt->PktLen || Len > CommPkt->PktLen) { return FALSE; } //
// Copy into the packet
//
CopyMemory(Dst, Src, Len); return TRUE; }
VOID CommCompletionRoutine( IN PCOMMAND_PACKET Cmd, IN PVOID Arg ) /*++
Routine Description: Completion routine for comm command servers. Free the comm packet and then call the generic completion routine to free the command packet.
Arguments: Cmd - command packet Arg - Cmd->CompletionArg
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommCompletionRoutine:"
PCOMM_PACKET CommPkt = SRCommPkt(Cmd); PCXTION Cxtion = SRCxtion(Cmd);
COMMAND_SND_COMM_TRACE(4, Cmd, Cmd->ErrorStatus, "SndComplete");
//
// The SndCs and the ReplicaCs cooperate to limit the number of
// active join "pings" so that the Snd threads are not hung
// waiting for pings to dead servers to time out.
//
if ((CommPkt != NULL) && (Cxtion != NULL) && (CommPkt == Cxtion->ActiveJoinCommPkt)) { Cxtion->ActiveJoinCommPkt = NULL; }
//
// Free the comm packet and the attached return response command packet if
// it's still attached. The Replica Cmd Server uses the CMD_JOINING_AFTER_FLUSH
// command in this way.
//
if (CommPkt != NULL) { FrsFree(CommPkt->Pkt); FrsFree(CommPkt); }
if (SRCmd(Cmd)) { FrsCompleteCommand(SRCmd(Cmd), Cmd->ErrorStatus); SRCmd(Cmd) = NULL; }
//
// Free the name/guid and Principal name params.
//
FrsFreeGName(SRTo(Cmd)); FrsFree(SRPrincName(Cmd));
//
// Move the packet to the generic "done" routine
//
FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL); FrsCompleteCommand(Cmd, Cmd->ErrorStatus); }
PUCHAR CommGetHdr( IN PUCHAR Pnext, IN PUSHORT PCommType, IN PULONG PLen ) /*++
Routine Description: Get and skip a field header
Arguments: Pnext PCommType PLen
Return Value: Address of the field's data --*/ { #undef DEBSUB
#define DEBSUB "CommGetHdr:"
CopyMemory(PCommType, Pnext, sizeof(USHORT)); Pnext += sizeof(USHORT);
CopyMemory(PLen, Pnext, sizeof(ULONG)); Pnext += sizeof(ULONG);
return Pnext; }
BOOL CommCheckPkt( IN PCOMM_PACKET CommPkt ) /*++
Routine Description: Check the packet for consistency
Arguments: CommPkt
Return Value: TRUE - consistent Otherwise - Assert failure --*/ { #undef DEBSUB
#define DEBSUB "CommCheckPkt:"
ULONG Len; ULONG Data; PUCHAR Pfirst; PUCHAR Pnext; PUCHAR Pend; USHORT CommType;
if (!CommPkt) { return FALSE; }
//
// Check major. Mismatched majors cannot be handled.
//
if (CommPkt->Major != NtFrsMajor) { DPRINT2(3, "WARN - RpcCommPkt: MAJOR MISMATCH %d major does not match %d; ignoring\n", CommPkt->Major, NtFrsMajor); return FALSE; } //
// Check minor. This service can process packets with mismatched
// minors, although some functionality may be lost.
//
if (CommPkt->Minor != NtFrsCommMinor) { DPRINT2(5, "RpcCommPkt: MINOR MISMATCH %d minor does not match %d\n", CommPkt->Minor, NtFrsCommMinor); }
//
// Compare the length of the packet with its memory allocation
//
if (CommPkt->PktLen > CommPkt->MemLen) { DPRINT2(4, "RpcCommPkt: Packet size (%d) > Alloced Memory (%d)\n", CommPkt->PktLen, CommPkt->MemLen); return FALSE; } //
// Must have at least a beginning-of-packet and end-of-packet field
//
if (CommPkt->PktLen < MIN_COMM_PACKET_SIZE) { DPRINT2(4, "RpcCommPkt: Packet size (%d) < Minimum size (%d)\n", CommPkt->PktLen, MIN_COMM_PACKET_SIZE); return FALSE; }
//
// packets begin with a beginning-of-packet
//
Pfirst = CommPkt->Pkt; Pnext = CommGetHdr(Pfirst, &CommType, &Len);
if (CommType != COMM_BOP || Len != sizeof(ULONG)) { return FALSE; }
CopyMemory(&Data, Pnext, sizeof(ULONG)); if (Data != 0) { return FALSE; }
//
// packets end with an end-of-packet
//
Pend = Pfirst + CommPkt->PktLen; if (Pend <= Pfirst) { return FALSE; } Pnext = ((Pend - sizeof(USHORT)) - sizeof(ULONG)) - sizeof(ULONG); Pnext = CommGetHdr(Pnext, &CommType, &Len);
if (CommType != COMM_EOP || Len != sizeof(ULONG)) { return FALSE; }
CopyMemory(&Data, Pnext, sizeof(ULONG));
if (Data != COMM_NULL_DATA) { return FALSE; }
return TRUE; }
VOID CommDumpCommPkt( IN PCOMM_PACKET CommPkt, IN DWORD NumDump ) /*++
Routine Description: Dump some of the comm packet
Arguments: CommPkt NumDump
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommDumpCommPkt:"
ULONG Len; PUCHAR Pnext; USHORT CommType; DWORD i;
DPRINT1(0, "%x:\n", CommPkt); DPRINT1(0, "\tMajor: %d\n", CommPkt->Major); DPRINT1(0, "\tMinor: %d\n", CommPkt->Minor); DPRINT1(0, "\tMemLen: %d\n", CommPkt->MemLen); DPRINT1(0, "\tPktLen: %d\n", CommPkt->PktLen); DPRINT1(0, "\tPkt: 0x%x\n", CommPkt->Pkt);
//
// packets begin with a beginning-of-packet
//
Pnext = CommPkt->Pkt; for (i = 0; i < NumDump; ++i) { Pnext = CommGetHdr(Pnext, &CommType, &Len); DPRINT4(0, "Dumping %d for %x: %d %d\n", i, CommPkt, CommType, Len); Pnext += Len; } }
VOID CommPackULong( IN PCOMM_PACKET CommPkt, IN COMM_TYPE Type, IN ULONG Data ) /*++
Routine Description: Copy a header and a ulong into the comm packet.
Arguments: CommPkt Type Data
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "CommPackULong:"
ULONG Len = sizeof(ULONG); USHORT CommType = (USHORT)Type;
CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)&Data, sizeof(ULONG)); }
PCOMM_PACKET CommStartCommPkt( IN PWCHAR Name ) /*++
Routine Description: Allocate a comm packet.
Arguments: Name
Return Value: Address of a comm packet. --*/ { #undef DEBSUB
#define DEBSUB "CommStartCommPkt:"
ULONG Size; PCOMM_PACKET CommPkt;
//
// We can create a comm packet in a file or in memory
//
CommPkt = FrsAlloc(sizeof(COMM_PACKET)); Size = COMM_MEM_SIZE; CommPkt->Pkt = FrsAlloc(Size); CommPkt->MemLen = Size; CommPkt->Major = NtFrsMajor; CommPkt->Minor = NtFrsCommMinor;
//
// Pack the beginning-of-packet
//
CommPackULong(CommPkt, COMM_BOP, 0); return CommPkt; }
BOOL CommUnpackBlob( IN PCOMM_PACKET CommPkt, OUT ULONG *OutBlobSize, OUT PVOID *OutBlob ) /*++
Routine Description: Unpack a blob (length + data)
Arguments: CommPkt OutBlobSize - size of blob from comm packet OutBlob - data from comm packet
Return Value: TRUE - Blob retrieved from comm packet FALSE - Blob was not retrieved from comm packet; bad comm packet --*/ { #undef DEBSUB
#define DEBSUB "CommUnpackBlob:"
ULONG BlobSize;
//
// Initialize return params
//
*OutBlob = NULL;
//
// Unpack the length of the blob
//
if (!CommFetchMemory(CommPkt, (PUCHAR)OutBlobSize, sizeof(ULONG))) { return FALSE; } BlobSize = *OutBlobSize;
//
// Empty blob, return NULL
//
if (BlobSize == 0) { return TRUE; }
//
// Allocate memory for the blob
//
*OutBlob = FrsAlloc(BlobSize);
//
// Unpack the blob
//
return CommFetchMemory(CommPkt, (PUCHAR)*OutBlob, BlobSize); }
BOOL CommUnpackGName( IN PCOMM_PACKET CommPkt, OUT PGNAME *OutGName ) /*++
Routine Description: Unpack the guid and wide char string that make up a gstring
Arguments: CommPkt OutGName - From comm packet
Return Value: TRUE - GName fetched from comm packet successfully FALSE - GName was not fetched from comm packet; bad comm packet --*/ { #undef DEBSUB
#define DEBSUB "CommUnpackGName:"
ULONG BlobSize; PGNAME GName;
//
// Allocate a gstring (caller cleans up on error)
//
*OutGName = GName = FrsAlloc(sizeof(GNAME));
if (!CommUnpackBlob(CommPkt, &BlobSize, &GName->Guid) || BlobSize != sizeof(GUID)) { return FALSE; }
if (!CommUnpackBlob(CommPkt, &BlobSize, &GName->Name) || GName->Name[(BlobSize / sizeof(WCHAR)) - 1] != L'\0') { return FALSE; }
return TRUE; }
BOOL CommGetNextElement( IN PCOMM_PACKET CommPkt, OUT COMM_TYPE *CommType, OUT ULONG *CommTypeSize ) /*++
Routine Description: Advance to the next field in the comm packet
Arguments: CommPkt CommType - type of packed field CommTypeSize - size of packed field (excluding type and size)
Return Value: TRUE - CommType and CommTypeSize were unpacked FALSE - Could not unpack; bad comm packet --*/ { #undef DEBSUB
#define DEBSUB "CommGetNextElement:"
USHORT Ushort;
//
// Find the type and length of this entry
//
if (CommFetchMemory(CommPkt, (PUCHAR)&Ushort, sizeof(USHORT)) && CommFetchMemory(CommPkt, (PUCHAR)CommTypeSize, sizeof(ULONG))) { *CommType = Ushort; return TRUE; } return FALSE; }
VOID CommInsertDataElement( IN PCOMM_PACKET CommPkt, IN COMM_TYPE CommType, IN PVOID CommData, IN ULONG CommDataLen ) /*++
Routine Description: Insert the data supplied using the CommType specific format into the Comm packet.
Arguments: CommPkt - The Comm packet structure. CommType - The data type for this element. CommData - The address of the data. CommDataLen - The size for var len elements.
Return Value: None.
--*/ { #undef DEBSUB
#define DEBSUB "CommInsertDataElement:"
ULONG Len; PGNAME GName; ULONG LenGuid; ULONG LenName; ULONG DataSize; ULONG DecodeType; PCHAR CommTag;
if (CommData == NULL) { return; }
FRS_ASSERT((CommType < COMM_MAX) && (CommType != COMM_NONE));
//
// Table index MUST match table CommType Field or table is fouled up.
//
FRS_ASSERT(CommType == CommPacketTable[CommType].CommType);
//
// Length check from table for fixed length fields.
//
//DataSize = CommPacketTable[CommType].DataSize;
//FRS_ASSERT((DataSize == COMM_SZ_NULL) || (CommDataLen == DataSize));
//
// Insert the data using the data type encoding.
//
DecodeType = CommPacketTable[CommType].DecodeType; CommTag = CommPacketTable[CommType].CommTag;
switch (DecodeType) {
//
// Insert a ULONG size piece of data.
//
case COMM_DECODE_ULONG: case COMM_DECODE_ULONG_TO_USHORT:
Len = sizeof(ULONG); DPRINT2(5, ":SR: Dec_long: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)CommData, sizeof(ULONG)); break;
//
// Insert a Guid and Name string (GNAME).
//
case COMM_DECODE_GNAME:
GName = (PGNAME)CommData; LenGuid = sizeof(GUID); LenName = (wcslen(GName->Name) + 1) * sizeof(WCHAR); Len = LenGuid + LenName + (2 * sizeof(ULONG)); DPRINT3(5, ":SR: Dec_gname: type: %s, len: %d - %ws\n", CommTag, Len, GName->Name); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)&LenGuid, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)GName->Guid, LenGuid); CommCopyMemory(CommPkt, (PUCHAR)&LenName, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)GName->Name, LenName); break;
//
// Insert a ULONGLONG.
//
case COMM_DECODE_ULONGLONG:
Len = sizeof(ULONGLONG); DPRINT2(5, ":SR: Dec_longlong: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)CommData, sizeof(ULONGLONG)); break;
//
// Insert a Guid.
//
case COMM_DECODE_GUID: Len = sizeof(GUID); DPRINT2(5, ":SR: Dec_Guid: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)CommData, sizeof(GUID)); break;
case COMM_DECODE_VVECTOR: //
// Version Vector data gets inserted into Comm packet as blobs.
//
NOTHING; /* FALL THRU INTENDED */
//
// Insert a variable length BLOB. The problem with blobs as currently
// shipped in win2k is that the code on the unpack side checks for a
// match on a constant length based on the COMM Data Type. This means
// that a var len datatype like CHANGE_ORDER_EXTENSION can't change because
// the 40 byte size is wired into the code of down level members. Sigh.
//
case COMM_DECODE_BLOB:
Len = CommDataLen + sizeof(ULONG); DPRINT2(5, ":SR: Dec_blob: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)&CommDataLen, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)CommData, CommDataLen); break;
//
// Insert a true variable length data struct that is extensible.
// The actual length comes from the first DWORD of the data.
//
case COMM_DECODE_VAR_LEN_BLOB:
Len = *(PULONG)CommData; DPRINT2(5, ":SR: Dec_var_len_blob: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)CommData, CommDataLen); break;
//
// The CO contains four pointers occupying 16 bytes on 32 bit architectures and
// 32 bytes on 64 bit architectures (PART2). When the CO is sent in a comm packet
// the contents of these pointers are irrelevant so in comm packets these
// ptrs are always sent as 16 bytes of zeros, regardless of architecture.
// Note - In 32 bit Win2k this was sent as a BLOB so it matches BLOB format.
//
case COMM_DECODE_REMOTE_CO:
Len = COMM_SZ_COC; CommDataLen = Len - sizeof(ULONG); DPRINT2(4, ":SR: Dec_remote_co: type: %s, len: %d\n", CommTag, Len); CommCopyMemory(CommPkt, (PUCHAR)&CommType, sizeof(USHORT)); CommCopyMemory(CommPkt, (PUCHAR)&Len, sizeof(ULONG)); CommCopyMemory(CommPkt, (PUCHAR)&CommDataLen, sizeof(ULONG));
CommCopyMemory(CommPkt, (PUCHAR)CommData, sizeof(CHANGE_ORDER_COMMAND));
//CommCopyMemory(CommPkt, ((PUCHAR)CommData)+CO_PART1_OFFSET, CO_PART1_SIZE);
//CommCopyMemory(CommPkt, NULL, CO_PART2_SIZE);
//CommCopyMemory(CommPkt, ((PUCHAR)CommData)+CO_PART3_OFFSET, CO_PART3_SIZE);
break;
default: //
// Table must be fouled up.
//
FRS_ASSERT((DecodeType > COMM_DECODE_NONE) && (DecodeType < COMM_DECODE_MAX));
break; }
return; }
PCOMM_PACKET CommBuildCommPkt( IN PREPLICA Replica, IN PCXTION Cxtion, IN ULONG Command, IN PGEN_TABLE VVector, IN PCOMMAND_PACKET Cmd, IN PCHANGE_ORDER_COMMAND Coc ) /*++
Routine Description: Generate a comm packet with the info needed to execute the command on the remote machine identified by Cxtion.
Arguments: Replica - Sender Cxtion - identifies the remote machine Command - command to execute on the remote machine VVector - some commands require the version vector Cmd - original command packet Coc - change order command RemoteGVsn - guid/vsn pair
Return Value: Address of a comm packet. --*/ { #undef DEBSUB
#define DEBSUB "CommBuildCommPkt:"
ULONGLONG FileTime; GNAME GName; PVOID Key; PCOMM_PACKET CommPkt; PGVSN GVsn; PGEN_ENTRY Entry;
//
// Allocate and initialize a comm packet
//
CommPkt = CommStartCommPkt(NULL); CommPkt->CsId = CS_RS;
CommInsertDataElement(CommPkt, COMM_COMMAND, &Command, 0); CommInsertDataElement(CommPkt, COMM_TO, Cxtion->Partner, 0); CommInsertDataElement(CommPkt, COMM_FROM, Replica->MemberName, 0);
GName.Guid = Cxtion->Partner->Guid; GName.Name = Replica->ReplicaName->Name; CommInsertDataElement(CommPkt, COMM_REPLICA, &GName, 0);
CommInsertDataElement(CommPkt, COMM_CXTION, Cxtion->Name, 0); CommInsertDataElement(CommPkt, COMM_JOIN_GUID, &Cxtion->JoinGuid, sizeof(GUID)); CommInsertDataElement(CommPkt, COMM_LAST_JOIN_TIME, &Cxtion->LastJoinTime, 0);
//
// Version vector (if supplied)
//
//
// The caller is building a comm packet for join operation,
// automatically include the current time and the originator guid.
//
if (VVector) { Key = NULL; while (GVsn = GTabNextDatum(VVector, &Key)) { CommInsertDataElement(CommPkt, COMM_VVECTOR, GVsn, sizeof(GVSN)); } GetSystemTimeAsFileTime((FILETIME *)&FileTime); CommInsertDataElement(CommPkt, COMM_JOIN_TIME, &FileTime, sizeof(ULONGLONG)); DPRINT1(4, ":X: Comm join time is %08x %08x\n", PRINTQUAD(FileTime)); CommInsertDataElement(CommPkt, COMM_REPLICA_VERSION_GUID, &Replica->ReplicaVersionGuid, sizeof(GUID)); //
// Insert the list of Guids for compression algorithms that we understand.
//
GTabLockTable(CompressionTable); Key = NULL; while (Entry = GTabNextEntryNoLock(CompressionTable, &Key)) { CommInsertDataElement(CommPkt, COMM_COMPRESSION_GUID, Entry->Key1, 0); } GTabUnLockTable(CompressionTable);
}
if (Cmd) { CommInsertDataElement(CommPkt, COMM_BLOCK, RsBlock(Cmd), (ULONG)RsBlockSize(Cmd)); CommInsertDataElement(CommPkt, COMM_BLOCK_SIZE, &RsBlockSize(Cmd), 0); CommInsertDataElement(CommPkt, COMM_FILE_SIZE, &RsFileSize(Cmd).QuadPart, 0); CommInsertDataElement(CommPkt, COMM_FILE_OFFSET, &RsFileOffset(Cmd).QuadPart, 0); CommInsertDataElement(CommPkt, COMM_GVSN, RsGVsn(Cmd), sizeof(GVSN)); CommInsertDataElement(CommPkt, COMM_CO_GUID, RsCoGuid(Cmd), sizeof(GUID)); CommInsertDataElement(CommPkt, COMM_CO_SEQUENCE_NUMBER, &RsCoSn(Cmd), 0); CommInsertDataElement(CommPkt, COMM_MD5_DIGEST, RsMd5Digest(Cmd), MD5DIGESTLEN); }
//
// Change Order Command
//
if (Coc) { CommInsertDataElement(CommPkt, COMM_REMOTE_CO, Coc, 0); //
// Warning: See comment in schema.h on CHANGE_ORDER_RECORD_EXTENSION for
// down level conversion info if Coc->Extension ever changes.
//
CommInsertDataElement(CommPkt, COMM_CO_EXT_WIN2K, Coc->Extension, sizeof(CO_RECORD_EXTENSION_WIN2K)); //
// For post win2k level members the CO extension info should be sent
// as follows since the length comes from the first dword of the data.
//
//CommInsertDataElement(CommPkt, COMM_CO_EXTENSION_2, Coc->Extension, 0);
}
//
// Terminate the packet with EOP Ulong.
//
CommPackULong(CommPkt, COMM_EOP, COMM_NULL_DATA);
return CommPkt; }
PCOMMAND_PACKET CommPktToCmd( IN PCOMM_PACKET CommPkt ) /*++
Routine Description: Unpack the data in a Comm packet and store it into a command struct.
Arguments: CommPkt
Return Value: Address of a command packet or NULL if unpack failed. --*/ { #undef DEBSUB
#define DEBSUB "CommPktToCmd:"
GUID *pTempGuid; PCOMMAND_PACKET Cmd = NULL; ULONG BlobSize; PVOID Blob; ULONG CommTypeSize; COMM_TYPE CommType; ULONG DataSize; ULONG DecodeType; ULONG NativeOffset; PUCHAR DataDest; ULONG TempUlong; BOOL b; GNAME GName; PCHAR CommTag; PUCHAR CommData; PGEN_TABLE GTable;
//
// Create the command packet
//
Cmd = FrsAllocCommand(&ReplicaCmdServer.Queue, CMD_UNKNOWN); FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
//
// Scan the comm packet from the beginning
//
CommPkt->UpkLen = 0; b = TRUE; while (CommGetNextElement(CommPkt, &CommType, &CommTypeSize) && CommType != COMM_EOP) {
//
// Uplevel members could send us comm packet data elements we don't handle.
//
if ((CommType >= COMM_MAX) || (CommType == COMM_NONE)) { DPRINT2(0, "++ WARN - Skipping invalid comm packet element type. CommType = %d, From %ws\n", CommType, RsFrom(Cmd) ? RsFrom(Cmd)->Name : L"<unknown>"); CommPkt->UpkLen += CommTypeSize; b = !(CommPkt->UpkLen > CommPkt->PktLen || CommTypeSize > CommPkt->PktLen); goto NEXT_ELEMENT; }
//
// Table index MUST match table CommType Field or table is fouled up.
//
FRS_ASSERT(CommType == CommPacketTable[CommType].CommType);
DataSize = CommPacketTable[CommType].DataSize;
if ((DataSize != COMM_SZ_NULL) && (CommTypeSize != DataSize)) { DPRINT3(0, "++ WARN - Invalid comm packet size. CommType = %d, DataSize = %d, From %ws\n", CommType, CommTypeSize, RsFrom(Cmd) ? RsFrom(Cmd)->Name : L"<unknown>"); goto CLEANUP_ON_ERROR; }
//
// Calc the data offset in the Cmd struct to store the data.
//
NativeOffset = CommPacketTable[CommType].NativeOffset; if (NativeOffset == RsOffsetSkip) { CommPkt->UpkLen += CommTypeSize; b = !(CommPkt->UpkLen > CommPkt->PktLen || CommTypeSize > CommPkt->PktLen); goto NEXT_ELEMENT; } DataDest = (PUCHAR) Cmd + NativeOffset;
//
// Decode the data element and store it in Cmd at the NativeOffset.
//
DecodeType = CommPacketTable[CommType].DecodeType; CommTag = CommPacketTable[CommType].CommTag;
//DPRINT6(5, ":SR: CommType: %s, Size: %d, Cmd offset: %d, data dest: %08x, Pkt->UpkLen = %d, Pkt->PktLen = %d\n",
// CommTag, CommTypeSize, NativeOffset,
// DataDest, CommPkt->UpkLen, CommPkt->PktLen);
switch (DecodeType) {
case COMM_DECODE_ULONG:
b = CommFetchMemory(CommPkt, DataDest, sizeof(ULONG));
DPRINT2(5, ":SR: rcv Dec_long: %s data: %d\n", CommTag, *(PULONG)DataDest); break;
case COMM_DECODE_ULONG_TO_USHORT:
b = CommFetchMemory(CommPkt, (PUCHAR)&TempUlong, sizeof(ULONG)); * ((PUSHORT) DataDest) = (USHORT)TempUlong; DPRINT2(5, ":SR: rcv Dec_ulong_to_ushort: %s data: %d\n", CommTag, TempUlong); break;
case COMM_DECODE_GNAME:
*(PVOID *)DataDest = FrsFreeGName(*(PVOID *)DataDest); b = CommUnpackGName(CommPkt, (PGNAME *) DataDest); GName.Guid = (*(PGNAME *)DataDest)->Guid; GName.Name = (*(PGNAME *)DataDest)->Name; DPRINT2(5, ":SR: rcv Dec_Gname: %s name: %ws\n", CommTag, GName.Name); break;
case COMM_DECODE_BLOB: case COMM_DECODE_VAR_LEN_BLOB:
*(PVOID *)DataDest = FrsFree(*(PVOID *)DataDest); b = CommUnpackBlob(CommPkt, &BlobSize, (PVOID *) DataDest); DPRINT1(5, ":SR: rcv Dec_blob: data: %08x\n", *(PULONG)DataDest); break;
case COMM_DECODE_ULONGLONG:
b = CommFetchMemory(CommPkt, DataDest, sizeof(ULONGLONG)); DPRINT2(5, ":SR: rcv Dec_long_long: %s data: %08x %08x\n", CommTag, PRINTQUAD(*(PULONGLONG)DataDest)); break;
//
// Version Vector data gets unpacked and inserted into Table.
//
case COMM_DECODE_VVECTOR: GTable = *(PGEN_TABLE *)(DataDest); if (GTable == NULL) { GTable = GTabAllocTable(); *(PGEN_TABLE *)(DataDest) = GTable; }
b = CommUnpackBlob(CommPkt, &BlobSize, &Blob); DPRINT2(5, ":SR: rcv Dec_VV: %s bloblen: %d\n", CommTag, BlobSize); if (b) { VVInsertOutbound(GTable, Blob); } break;
//
// Compression Guid data gets unpacked and inserted into table.
//
case COMM_DECODE_GUID: if (CommType == COMM_COMPRESSION_GUID) { GTable = *(PGEN_TABLE *)(DataDest); if (GTable == NULL) { GTable = GTabAllocTable(); *(PGEN_TABLE *)(DataDest) = GTable; }
pTempGuid = FrsAlloc(sizeof(GUID));
b = CommFetchMemory(CommPkt, (PUCHAR)pTempGuid, sizeof(GUID)); DPRINT2(5, ":SR: rcv Comp_Guid: %s bloblen: %d\n", CommTag, BlobSize); if (b) { GTabInsertEntry(GTable, NULL, pTempGuid, NULL); }
} else { //
// Else the guid gets stashed in the data dest.
//
b = CommFetchMemory(CommPkt, DataDest, sizeof(GUID)); DPRINT1(5, ":SR: rcv Guid: %s \n", CommTag); } break;
//
// The CO contains four pointers occupying 16 bytes on 32 bit architectures
// and 32 bytes on 64 bit architectures (PART2). When the CO is sent
// in a comm packet the contents of these pointers are irrelevant so in
// comm packets these ptrs are always sent as 16 bytes of zeros,
// regardless of architecture.
// Note - In 32 bit Win2k this was sent as a BLOB so it matches BLOB format.
//
case COMM_DECODE_REMOTE_CO:
*(PVOID *)DataDest = FrsFree(*(PVOID *)DataDest); //
// Unpack the length of the CO and then unpack the CO data.
//
b = CommFetchMemory(CommPkt, (PUCHAR)&BlobSize, sizeof(ULONG)); if (!b || (BlobSize == 0)) { break; }
CommData = FrsAlloc(sizeof(CHANGE_ORDER_COMMAND));
CommFetchMemory(CommPkt, (PUCHAR)CommData, sizeof(CHANGE_ORDER_COMMAND));
//CommFetchMemory(CommPkt, ((PUCHAR)CommData)+CO_PART1_OFFSET, CO_PART1_SIZE);
//CommFetchMemory(CommPkt, ((PUCHAR)CommData)+CO_PART2_OFFSET, CO_PART2_SIZE);
//CommFetchMemory(CommPkt, ((PUCHAR)CommData)+CO_PART3_OFFSET, CO_PART3_SIZE);
DPRINT2(4, ":SR: rcv remote_co: type: %s, len: %d\n", CommTag, BlobSize);
*(PVOID *) DataDest = CommData; break;
default: //
// Decode data type from an uplevel client. Although we should
// not really get here because uplevel clients should only be using
// new decode data types with new decode data elements which got
// filtered out above.
//
DPRINT3(0, "++ WARN - Skipping invalid comm packet decode data type. CommType = %d, DecodeType = %d, From %ws\n", CommType, DecodeType, RsFrom(Cmd) ? RsFrom(Cmd)->Name : L"<unknown>"); CommPkt->UpkLen += CommTypeSize; b = !(CommPkt->UpkLen > CommPkt->PktLen || CommTypeSize > CommPkt->PktLen);
break; }
NEXT_ELEMENT:
if (!b) { DPRINT4(0, ":SR: PKT ERROR -- CommType = %s, DataSize = %d, CommPkt->UpkLen = %d, CommPkt->PktLen = %d\n", CommTag, CommTypeSize, CommPkt->UpkLen, CommPkt->PktLen); goto CLEANUP_ON_ERROR; } }
//
// SUCCESS
//
return Cmd;
//
// FAILURE
//
CLEANUP_ON_ERROR: if (Cmd) { FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED); } return NULL; }
|