|
|
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
dgpkt.hxx
Abstract:
This file contains the definitions for a dg packet.
Author:
Dave Steckler (davidst) 3-Mar-1992
Revision History:
--*/
#ifndef __DGPKT_HXX__
#define __DGPKT_HXX__
#include <rpctran.h>
#include <limits.h>
#if defined(NTENV) || defined(WIN96)
#define MULTITHREADED
#include <threads.hxx>
#include <delaytab.hxx>
extern DELAYED_ACTION_NODE * GlobalScavengerTimer; extern DELAYED_ACTION_TABLE * DelayedActions;
extern void GlobalScavengerProc( void * Unused );
#endif // 32-bit platform
#define DG_RPC_PROTOCOL_VERSION 4
#define MAX_WINDOW_SIZE (CHAR_BIT * sizeof(unsigned))
//
// delay times
//
#define TWO_SECS_IN_MSEC (2 * 1000)
#define THREE_SECS_IN_MSEC (3 * 1000)
#define TEN_SECS_IN_MSEC (10 * 1000)
#define FIFTEEN_SECS_IN_MSEC (15 * 1000)
#define ONE_MINUTE_IN_MSEC (60 * 1000)
#define FIVE_MINUTES_IN_MSEC (5 * 60 * 1000)
inline unsigned long CurrentTimeInMsec( void ) { #ifdef MULTITHREADED
return GetTickCount(); #else
return 0; #endif
}
// PacketType values:
#define DG_REQUEST 0
#define DG_PING 1
#define DG_RESPONSE 2
#define DG_FAULT 3
#define DG_WORKING 4
#define DG_NOCALL 5
#define DG_REJECT 6
#define DG_ACK 7
#define DG_QUIT 8
#define DG_FACK 9
#define DG_QUACK 10
// PacketFlags values:
#define DG_PF_INIT 0x0000
#define DG_PF_FORWARDED 0x0001
#define DG_PF_LAST_FRAG 0x0002
#define DG_PF_FRAG 0x0004
#define DG_PF_NO_FACK 0x0008
#define DG_PF_MAYBE 0x0010
#define DG_PF_IDEMPOTENT 0x0020
#define DG_PF_BROADCAST 0x0040
// In the AES this bit is "reserved for implementations"
//
#define DG_PF_OVERSIZE_PACKET 0x0080
// for PacketFlags2:
#define DG_PF_FORWARDED_2 0x0001
#define DG_PF_CANCEL_PENDING 0x0002
// for DREP[0]:
#define DG_DREP_CHAR_ASCII 0
#define DG_DREP_CHAR_EBCDIC 1
#define DG_DREP_INT_BIG 0
#define DG_DREP_INT_LITTLE 16
// for DREP[1]
#define DG_DREP_FP_IEEE 0
#define DG_DREP_FP_VAX 1
#define DG_DREP_FP_CRAY 2
#define DG_DREP_FP_IBM 3
#define DG_MSG_DREP_INITIALIZE 0x11111100
#define NDR_DREP_ENDIAN_MASK 0xF0
#define RPC_NCA_PACKET_FLAGS (RPC_NCA_FLAGS_IDEMPOTENT | RPC_NCA_FLAGS_BROADCAST | RPC_NCA_FLAGS_MAYBE)
//
// The RPC packet header and security verifier must each be 8-aligned.
//
#define PACKET_HEADER_ALIGNMENT (8)
#define SECURITY_HEADER_ALIGNMENT (8)
extern const unsigned RpcToPacketFlagsArray[]; extern const unsigned PacketToRpcFlagsArray[];
extern unsigned DefaultSocketBufferLength; extern unsigned DefaultMaxDatagramSize;
//
// Controls on the number of packets in the packet cache.
// Note that these values are for each packet size, not the
// cache as a whole.
//
#ifndef NO_PACKET_CACHE
#define MIN_FREE_PACKETS 3
#if defined(__RPC_DOS__)
#define MAX_FREE_PACKETS 8
#elif defined(__RPC_WIN16__)
#define MAX_FREE_PACKETS 20
#else
#define MAX_FREE_PACKETS 1000
#endif
#else
#define MIN_FREE_PACKETS 0
#define MAX_FREE_PACKETS 0
#endif
#if defined(DOS) && !defined(WIN)
typedef long LONG; typedef long PAPI * PLONG;
#endif // Windows
#if defined(MAC)
typedef long LONG; typedef long PAPI * PLONG;
#endif // Windows
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
typedef unsigned char boolean;
//-------------------------------------------------------------------
char __RPC_FAR * AllocateLargeBuffer( unsigned Size );
void FreeLargeBuffer( void __RPC_FAR * Ptr );
extern unsigned long __RPC_FAR MapToNcaStatusCode ( IN RPC_STATUS RpcStatus );
extern RPC_STATUS __RPC_FAR MapFromNcaStatusCode ( IN unsigned long NcaStatus );
inline unsigned PacketToRpcFlags( unsigned PacketFlags ) { return PacketToRpcFlagsArray[(PacketFlags >> 4) & 7]; }
#ifndef WIN32
inline LONG InterlockedExchange( LONG * pDest, LONG New ) { LONG Old = *pDest;
*pDest = New;
return Old; }
inline LONG InterlockedIncrement( LONG * pDest ) { LONG Old = *pDest;
*pDest = 1+Old;
return Old; }
inline LONG InterlockedDecrement( LONG * pDest ) { LONG Old = *pDest;
*pDest = -1+Old;
return Old; }
#endif // !NTENV
//-------------------------------------------------------------------
struct DG_SECURITY_TRAILER { unsigned char protection_level; unsigned char key_vers_num; };
typedef DG_SECURITY_TRAILER __RPC_FAR * PDG_SECURITY_TRAILER;
struct FACK_BODY_VER_0 { // FACK body version; we understand only zero.
//
unsigned char Version;
// pad byte
//
unsigned char Pad1;
// Window size, in kilobytes.
// BUGBUG AES/DC contradicts itself on page 12-18; is it kilobytes or packets?
//
unsigned short WindowSize;
// Largest datagram the sender can handle, in bytes.
//
unsigned long MaxDatagramSize;
// Largest datagram that won't be fragmented over the wire, in bytes.
//
unsigned long MaxPacketSize;
// Serial number of packet that caused this FACK.
//
unsigned short SerialNumber;
// Number of unsigned longs in the Acks[] array.
//
unsigned short AckWordCount;
#pragma warning(disable:4200)
// Array of bit masks.
//
unsigned long Acks[0];
#pragma warning(default:4200)
};
void ByteSwapFackBody0( FACK_BODY_VER_0 __RPC_FAR * pBody );
typedef unsigned char DREP[4];
//
// The following structure is the NCA Datagram RPC packet header.
//
struct _NCA_PACKET_HEADER { unsigned char RpcVersion; unsigned char PacketType; unsigned char PacketFlags; unsigned char PacketFlags2; DREP DataRep; RPC_UUID ObjectId; RPC_UUID InterfaceId; RPC_UUID ActivityId; unsigned long ServerBootTime; RPC_VERSION InterfaceVersion; unsigned long SequenceNumber; unsigned short OperationNumber; unsigned short InterfaceHint; unsigned short ActivityHint; unsigned short PacketBodyLen; unsigned short FragmentNumber; unsigned char AuthProto; unsigned char SerialLo;
#pragma warning(disable:4200)
unsigned char Data[0];
#pragma warning(default:4200)
};
typedef struct _NCA_PACKET_HEADER NCA_PACKET_HEADER, PAPI * PNCA_PACKET_HEADER;
struct QUIT_BODY_0 { unsigned long Version; unsigned long EventId; };
struct QUACK_BODY_0 { unsigned long Version; unsigned long EventId; unsigned char Accepted; };
class DG_PACKET; typedef DG_PACKET PAPI * PDG_PACKET;
class __RPC_FAR DG_PACKET
/*++
Class Description:
This class represents a packet that will be sent or received on the network.
Fields:
pTransAddress - A pointer to either a DG_CLIENT_TRANS_ADDRESS or a DG_SERVER_TRANS_ADDRESS that this packet will be sent or received through.
pNcaPacketHeader - Where the packet information goes. Marshalled data follows immediately after this header.
DataLength - Length of the marshalled data.
TimeReceive - Time in seconds that this packet was received. This is filled in by the transport.
pNext, pPrevious - Used to keep these packets in a list.
--*/
{ public:
unsigned MaxDataLength; unsigned DataLength; DG_PACKET * pNext; DG_PACKET * pPrevious;
unsigned Flags;
// Tick count when the packet was added to the free list.
//
unsigned TimeReceived;
// WARNING: Header must be 8-byte-aligned.
//
NCA_PACKET_HEADER Header;
//--------------------------------------------------------------------
DG_PACKET( unsigned PacketLength );
~DG_PACKET();
void PAPI * operator new( size_t ObjectSize, unsigned BufferLength );
void operator delete( void PAPI * UserBuffer, size_t ObjectSize );
static PDG_PACKET AllocatePacket( unsigned BufferLength );
static void FreePacket( PDG_PACKET pPacket );
static unsigned ScavengePackets( unsigned Age );
static void FlushPacketLists( );
static RPC_STATUS Initialize( );
inline static PDG_PACKET ContainingRecord( void __RPC_FAR * Buffer ) { return CONTAINING_RECORD (Buffer, DG_PACKET, Header.Data); }
private:
enum { NUMBER_OF_PACKET_LISTS = 6 };
struct PACKET_LIST { unsigned PacketLength; unsigned Count; PDG_PACKET Head; };
static MUTEX * PacketListMutex; static PACKET_LIST PacketLists[NUMBER_OF_PACKET_LISTS];
};
inline DG_PACKET::DG_PACKET( unsigned PacketLength ) { MaxDataLength = PacketLength; }
inline DG_PACKET::~DG_PACKET() { }
inline void PAPI * DG_PACKET::operator new( size_t ObjectSize, unsigned BufferLength ) /*++
Routine Description:
Allocates a DG_PACKET with the specified buffer size.
Arguments:
ObjectSize - generated by compiler; same as sizeof(DG_PACKET)
BufferLength - PDU size, including NCA header
Return Value:
an 8-byte-aligned pointer to an obect of the requested size
--*/
{ unsigned Size = ObjectSize + BufferLength - sizeof(NCA_PACKET_HEADER);
return AllocateLargeBuffer(Size); }
inline void DG_PACKET::operator delete( void PAPI * UserBuffer, size_t ObjectSize ) { FreeLargeBuffer(UserBuffer); }
void ByteSwapPacketHeader( PDG_PACKET pPacket );
inline BOOL NeedsByteSwap( PNCA_PACKET_HEADER pHeader ) { #ifdef __RPC_MAC__
if (pHeader->DataRep[0] & DG_DREP_INT_LITTLE) { return TRUE; } else { return FALSE; } #else
if (pHeader->DataRep[0] & DG_DREP_INT_LITTLE) { return FALSE; } else { return TRUE; } #endif
}
inline void ByteSwapPacketHeaderIfNecessary( PDG_PACKET pPacket ) { if (NeedsByteSwap(&pPacket->Header)) { ByteSwapPacketHeader(pPacket); } }
#define ByteSwapLong(Value) \
Value = ( (((Value) & 0xFF000000) >> 24) \ | (((Value) & 0x00FF0000) >> 8) \ | (((Value) & 0x0000FF00) << 8) \ | (((Value) & 0x000000FF) << 24))
#define ByteSwapShort(Value) \
Value = ( (((Value) & 0x00FF) << 8) \ | (((Value) & 0xFF00) >> 8))
inline unsigned short ReadSerialNumber( PNCA_PACKET_HEADER pHeader ) { unsigned short SerialNum = 0;
SerialNum = pHeader->SerialLo; SerialNum |= (pHeader->DataRep[3] << 8);
return SerialNum; }
inline void SetMyDataRep( PNCA_PACKET_HEADER pHeader ) { #ifdef __RPC_MAC__
pHeader->DataRep[0] = DG_DREP_CHAR_ASCII | DG_DREP_INT_BIG; pHeader->DataRep[1] = DG_DREP_FP_IEEE; pHeader->DataRep[2] = 0; #else
pHeader->DataRep[0] = DG_DREP_CHAR_ASCII | DG_DREP_INT_LITTLE; pHeader->DataRep[1] = DG_DREP_FP_IEEE; pHeader->DataRep[2] = 0; #endif
}
inline char __RPC_FAR * AllocateLargeBuffer( unsigned Size ) /*++
Routine Description:
Rpc Stubs expect buffers to be 8 [ALIGN_REQUIRED] aligned NT allocator does this by default DOS/WIN allocators are 2 bytes aligned and we need to allign here appropriately This routine exists only for DOS and WINDOWS
Arguments:
Size - size of memoryblock reqd.
Return Value:
Buffer that is allocated or 0
--*/ { #ifdef NTENV
return new char[Size]; #else
void PAPI * RealBuffer; char pad;
RealBuffer = RpcpFarAllocate(Size + PACKET_HEADER_ALIGNMENT); if (RealBuffer == 0) { return 0; }
ASSERT(PACKET_HEADER_ALIGNMENT == 8);
pad = Pad((char __RPC_FAR *)RealBuffer + 1, PACKET_HEADER_ALIGNMENT) + 1; ASSERT(pad > 0 && pad <= PACKET_HEADER_ALIGNMENT);
char PAPI * UserBuffer = (char PAPI *) RealBuffer; UserBuffer += pad; UserBuffer[-1] = pad;
ASSERT(Align8(UserBuffer) == UserBuffer);
return UserBuffer; #endif
}
inline void FreeLargeBuffer( void __RPC_FAR * Ptr ) { #ifdef NTENV
delete Ptr; #else
char PAPI * RealPointer = (char PAPI *) Ptr;
ASSERT(RealPointer[-1] <= PACKET_HEADER_ALIGNMENT);
RealPointer -= RealPointer[-1];
RpcpFarFree(RealPointer); #endif
}
inline void DeleteSpuriousAuthProto( PDG_PACKET pPacket ) /*++
Routine Description:
Some versions of OSF DCE generate packets that specify an auth proto, but do not actually have an auth trailer. They should be interpreted as unsecure packets.
Arguments:
the packet to clean up
Return Value:
none
--*/
{ if (pPacket->Header.AuthProto != 0 && pPacket->Header.PacketBodyLen == pPacket->DataLength) { pPacket->Header.AuthProto = 0; } }
class DG_ASSOCIATION { public:
unsigned short CurrentPduSize; unsigned short RemoteWindowSize;
DG_ASSOCIATION( unsigned a_InitialPduSize, RPC_STATUS __RPC_FAR * pStatus ) : ReferenceCount (1), RemoteWindowSize (1), CurrentPduSize (a_InitialPduSize), Mutex (pStatus) { }
void IncrementRefCount( ) { ReferenceCount.Increment(); }
long DecrementRefCount( ) { return ReferenceCount.Decrement(); }
void RequestMutex( ) { Mutex.Request(); }
void ClearMutex( ) { Mutex.Clear(); }
void SetMaxPduSize( unsigned PduSize ) { CurrentPduSize = PduSize; }
unsigned InqMaxPduSize( ) { return CurrentPduSize; }
protected:
INTERLOCKED_INTEGER ReferenceCount; MUTEX Mutex; };
typedef DG_ASSOCIATION * PDG_ASSOCIATION;
class DG_PACKET_ENGINE { public:
unsigned short ActivityHint;
unsigned short InterfaceHint;
unsigned long SequenceNumber;
PDG_PACKET pSavedPacket;
//--------------------------------------------------------------------
DG_PACKET_ENGINE::DG_PACKET_ENGINE( unsigned short a_CurrentPduSize, unsigned short a_MaxPduSize, unsigned short a_MaxPacketSize, unsigned short a_SendWindowSize, unsigned a_TransportBufferLength, RPC_STATUS __RPC_FAR * pStatus );
~DG_PACKET_ENGINE( );
void NewCall( );
RPC_STATUS SetupSendWindow( PRPC_MESSAGE Message );
void CleanupReceiveWindow( );
RPC_STATUS SendSomeFragments( unsigned char PacketType );
RPC_STATUS SendFragment( unsigned FragNum, unsigned char PacketType, BOOL fFack );
virtual RPC_STATUS SealAndSendPacket( PNCA_PACKET_HEADER pHeader ) = 0;
RPC_STATUS SendFack( PDG_PACKET pPacket );
void UpdateSendWindow( PDG_PACKET pPacket, PSECURITY_CONTEXT pSecurityContext, PDG_ASSOCIATION Association );
BOOL UpdateReceiveWindow( PDG_PACKET pPacket );
RPC_STATUS AssembleBufferFromPackets( IN OUT PRPC_MESSAGE pMessage, CONNECTION * pConn );
void SetFragmentLengths( SECURITY_CONTEXT * SecurityContext );
inline void RecalcFragmentSize( );
void RecalcPduSize( );
BOOL ReceivedAllFrags( );
unsigned short LastConsecutiveFragment( ) { if (0 == pLastConsecutivePacket) { return 0xffff; } else { return pLastConsecutivePacket->Header.FragmentNumber; } }
void MarkAllPacketsReceived( ) { SendWindowBase = FinalSendFrag+1; }
BOOL IsBufferAcknowledged( ) { if (SendWindowBase > FinalSendFrag) { return TRUE; }
return FALSE; }
BOOL IsBufferSent( ) { if (FirstUnsentFragment > FinalSendFrag) { return TRUE; }
return FALSE; }
inline void AddSerialNumber( PNCA_PACKET_HEADER pHeader );
protected:
PDG_PACKET AllocatePacket( ) { return DG_PACKET::AllocatePacket(MaxPduSize); }
void FreePacket( PDG_PACKET Packet ) { DG_PACKET::FreePacket(Packet); }
//
//--------------data common to send and receive buffers-------------------
//
//
// Biggest datagram the transport can send or receive, possibly
// with fragmentation and reassembly.
//
unsigned short MaxPduSize;
//
// Biggest packet that transport won't fragment.
//
unsigned short MaxPacketSize;
//
// Largest PDU that this object will send.
//
unsigned short CurrentPduSize;
//
// Value of CurrentPduSize for the next RPC call.
//
unsigned short NextCallPduSize;
//
// Number of bytes of stub data in a datagram.
//
unsigned short MaxFragmentSize;
//
// Number of bytes of security trailer in a datagram.
//
unsigned short SecurityTrailerSize;
//
// number of consecutive unacknowledged packets, including retransmissions
//
unsigned TimeoutCount;
unsigned short SendSerialNumber;
unsigned short ReceiveSerialNumber;
unsigned long CancelEventId;
LONG Cancelled;
#ifdef MULTITHREADED
BOOL CancelPending; #endif
//
// -------------------data concerning send buffer-------------------------
//
void PAPI * Buffer;
unsigned BufferLength;
unsigned long BufferFlags;
//
// maximum number of packets in send window
//
unsigned short SendWindowSize;
//
// number of packets to transmit in one shot
//
unsigned short SendBurstLength;
//
// lowest unacknowledged fragment
//
unsigned short SendWindowBase;
//
// first fragment that has never been sent
//
unsigned short FirstUnsentFragment;
//
// Buffer offset of FirstUnsentFragment.
//
unsigned FirstUnsentOffset;
//
// bit mask showing which fragments to send
// (same format as in FACK packet with body)
//
unsigned SendWindowBits;
//
// For each unacknowledged fragment, we need to know the serial number
// of the last retransmission. When a FACK arrives, we will retransmit
// only those packets with a serial number less than that of the FACK.
//
struct { unsigned short SerialNumber; unsigned short Length; unsigned Offset; } FragmentRingBuffer[MAX_WINDOW_SIZE];
unsigned RingBufferBase;
//
// last fragment of buffer
//
unsigned short FinalSendFrag;
// serial number of last packet FACKed by other end
//
unsigned short FackSerialNumber;
//
// ----------------data concerning receive buffer-------------------------
//
//
// all received packets
//
PDG_PACKET pReceivedPackets;
//
// last packet before a gap
//
PDG_PACKET pLastConsecutivePacket;
//
// maximum number of packets in receive window
//
unsigned short ReceiveWindowSize;
//
// First fragment we should keep. Elder fragments belong to a previous
// pipe buffer.
//
unsigned short ReceiveFragmentBase;
//
// Length of the underlying transport's socket buffer.
//
unsigned TransportBufferLength;
//
// Number of bytes in consecutive fragments.
//
unsigned ConsecutiveDataBytes;
//
// The last-allocated pipe receive buffer, and its length.
//
void __RPC_FAR *LastReceiveBuffer; unsigned LastReceiveBufferLength;
boolean fReceivedAllFragments; boolean fRetransmitted; };
inline void SetSerialNumber( PNCA_PACKET_HEADER pHeader, unsigned short SerialNumber ) { pHeader->SerialLo = SerialNumber & 0x00ffU; pHeader->DataRep[3] = (unsigned char) (SerialNumber >> 8); }
inline void DG_PACKET_ENGINE::AddSerialNumber( PNCA_PACKET_HEADER pHeader ) { SetSerialNumber(pHeader, SendSerialNumber); }
//------------------------------------------------------------------------
RPC_STATUS VerifySecurePacket( PDG_PACKET pPacket, SECURITY_CONTEXT * pSecurityContext );
#endif // __DGPKT_HXX__
|