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.
1716 lines
40 KiB
1716 lines
40 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
dgpkt.cxx
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Author:
|
|
|
|
Jeff Roberts (jroberts) 22-May-1995
|
|
|
|
Revision History:
|
|
|
|
22-May-1995 jroberts
|
|
|
|
Created this module.
|
|
|
|
--*/
|
|
|
|
#include <precomp.hxx>
|
|
#include <dgpkt.hxx>
|
|
|
|
|
|
const unsigned
|
|
RpcToPacketFlagsArray[8] =
|
|
{
|
|
0,
|
|
DG_PF_IDEMPOTENT,
|
|
DG_PF_BROADCAST,
|
|
DG_PF_IDEMPOTENT | DG_PF_BROADCAST,
|
|
DG_PF_MAYBE,
|
|
DG_PF_IDEMPOTENT | DG_PF_MAYBE,
|
|
DG_PF_BROADCAST | DG_PF_MAYBE,
|
|
DG_PF_IDEMPOTENT | DG_PF_BROADCAST | DG_PF_MAYBE,
|
|
};
|
|
|
|
const unsigned
|
|
PacketToRpcFlagsArray[8] =
|
|
{
|
|
0 | 0 | 0 ,
|
|
RPC_NCA_FLAGS_MAYBE | 0 | 0 ,
|
|
0 | RPC_NCA_FLAGS_IDEMPOTENT | 0 ,
|
|
RPC_NCA_FLAGS_MAYBE | RPC_NCA_FLAGS_IDEMPOTENT | 0 ,
|
|
0 | 0 | RPC_NCA_FLAGS_BROADCAST,
|
|
RPC_NCA_FLAGS_MAYBE | 0 | RPC_NCA_FLAGS_BROADCAST,
|
|
0 | RPC_NCA_FLAGS_IDEMPOTENT | RPC_NCA_FLAGS_BROADCAST,
|
|
RPC_NCA_FLAGS_MAYBE | RPC_NCA_FLAGS_IDEMPOTENT | RPC_NCA_FLAGS_BROADCAST,
|
|
};
|
|
|
|
|
|
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
|
|
)
|
|
: ActivityHint (0xffff),
|
|
InterfaceHint (0xffff),
|
|
SequenceNumber (0),
|
|
|
|
CurrentPduSize (a_CurrentPduSize),
|
|
NextCallPduSize (a_CurrentPduSize),
|
|
MaxFragmentSize (a_CurrentPduSize-sizeof(NCA_PACKET_HEADER)),
|
|
SecurityTrailerSize (0),
|
|
|
|
MaxPacketSize (a_MaxPacketSize),
|
|
MaxPduSize (a_MaxPduSize),
|
|
|
|
TransportBufferLength (a_TransportBufferLength),
|
|
SendWindowSize (a_SendWindowSize),
|
|
|
|
Buffer (0),
|
|
BufferLength (0),
|
|
|
|
// other send window data will be init'ed when buffer is available
|
|
|
|
#ifdef MULTITHREADED
|
|
|
|
CancelPending (FALSE),
|
|
Cancelled (FALSE),
|
|
|
|
#endif
|
|
pReceivedPackets (0),
|
|
pLastConsecutivePacket(0),
|
|
ConsecutiveDataBytes (0),
|
|
ReceiveFragmentBase (0)
|
|
|
|
// other receive window data will be init'ed when buffer is available
|
|
|
|
{
|
|
if (*pStatus)
|
|
{
|
|
pSavedPacket = 0;
|
|
return;
|
|
}
|
|
|
|
pSavedPacket = AllocatePacket();
|
|
if (!pSavedPacket)
|
|
{
|
|
*pStatus = RPC_S_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
|
|
pSavedPacket->Header.RpcVersion = DG_RPC_PROTOCOL_VERSION;
|
|
pSavedPacket->Header.ActivityHint = 0xffff;
|
|
pSavedPacket->Header.InterfaceHint = 0xffff;
|
|
|
|
SetMyDataRep(&pSavedPacket->Header);
|
|
}
|
|
|
|
DG_PACKET_ENGINE::~DG_PACKET_ENGINE(
|
|
)
|
|
{
|
|
if (pSavedPacket)
|
|
{
|
|
FreePacket(pSavedPacket);
|
|
}
|
|
|
|
CleanupReceiveWindow();
|
|
}
|
|
|
|
|
|
inline void
|
|
DG_PACKET_ENGINE::RecalcFragmentSize(
|
|
)
|
|
{
|
|
MaxFragmentSize = CurrentPduSize - sizeof(NCA_PACKET_HEADER);
|
|
|
|
if (SecurityTrailerSize)
|
|
{
|
|
MaxFragmentSize -= SecurityTrailerSize;
|
|
MaxFragmentSize -= MaxFragmentSize % SECURITY_HEADER_ALIGNMENT;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET_ENGINE::NewCall(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A new call dawns.
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
RecalcPduSize();
|
|
|
|
fReceivedAllFragments = FALSE;
|
|
fRetransmitted = FALSE;
|
|
|
|
TimeoutCount = 0;
|
|
|
|
FackSerialNumber = 0;
|
|
SendSerialNumber = 0;
|
|
ReceiveSerialNumber = 0;
|
|
|
|
SendWindowBase = 0;
|
|
FirstUnsentFragment = 0;
|
|
SendBurstLength = SendWindowSize;
|
|
|
|
RingBufferBase = 0;
|
|
|
|
CleanupReceiveWindow();
|
|
ReceiveFragmentBase = 0;
|
|
|
|
ReceiveWindowSize = TransportBufferLength / CurrentPduSize;
|
|
|
|
LastReceiveBuffer = 0;
|
|
LastReceiveBufferLength = 0;
|
|
|
|
#ifdef DEBUGRPC
|
|
|
|
for (unsigned i=0; i < MAX_WINDOW_SIZE; i++)
|
|
{
|
|
FragmentRingBuffer[i].SerialNumber = 0xe000;
|
|
FragmentRingBuffer[i].Length = 0xd000;
|
|
FragmentRingBuffer[i].Offset = 0xb000b000;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_PACKET_ENGINE::SetupSendWindow(
|
|
PRPC_MESSAGE Message
|
|
)
|
|
{
|
|
RecalcPduSize();
|
|
|
|
Buffer = Message->Buffer;
|
|
BufferLength = Message->BufferLength;
|
|
BufferFlags = Message->RpcFlags;
|
|
|
|
//
|
|
// Accumulate data until we have enough to fill the send window.
|
|
//
|
|
if ((BufferFlags & RPC_BUFFER_PARTIAL) &&
|
|
BufferLength < MaxFragmentSize * SendWindowSize )
|
|
{
|
|
Buffer = 0;
|
|
return RPC_S_SEND_INCOMPLETE;
|
|
}
|
|
|
|
//
|
|
// A partial send will send only whole fragments.
|
|
//
|
|
if (Message->RpcFlags & RPC_BUFFER_PARTIAL)
|
|
{
|
|
BufferLength -= BufferLength % MaxFragmentSize;
|
|
}
|
|
|
|
TimeoutCount = 0;
|
|
SendWindowBits = 0;
|
|
FirstUnsentOffset = 0;
|
|
|
|
if (BufferLength == 0)
|
|
{
|
|
FinalSendFrag = SendWindowBase;
|
|
}
|
|
else
|
|
{
|
|
FinalSendFrag = SendWindowBase + (BufferLength-1) / MaxFragmentSize;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET_ENGINE::RecalcPduSize(
|
|
)
|
|
{
|
|
if (CurrentPduSize != NextCallPduSize)
|
|
{
|
|
if (NextCallPduSize <= pSavedPacket->MaxDataLength)
|
|
{
|
|
CurrentPduSize = NextCallPduSize;
|
|
RecalcFragmentSize();
|
|
}
|
|
else
|
|
{
|
|
PDG_PACKET Temp = DG_PACKET::AllocatePacket(NextCallPduSize);
|
|
if (Temp)
|
|
{
|
|
RpcpMemoryCopy(&Temp->Header, &pSavedPacket->Header, sizeof(Temp->Header));
|
|
DG_PACKET::FreePacket(pSavedPacket);
|
|
pSavedPacket = Temp;
|
|
|
|
CurrentPduSize = NextCallPduSize;
|
|
RecalcFragmentSize();
|
|
}
|
|
else
|
|
{
|
|
NextCallPduSize = CurrentPduSize;
|
|
}
|
|
}
|
|
|
|
ReceiveWindowSize = TransportBufferLength / CurrentPduSize;
|
|
}
|
|
}
|
|
|
|
void
|
|
DG_PACKET_ENGINE::CleanupReceiveWindow(
|
|
)
|
|
{
|
|
//
|
|
// Free any response packets.
|
|
//
|
|
while (pReceivedPackets)
|
|
{
|
|
PDG_PACKET Next = pReceivedPackets->pNext;
|
|
FreePacket(pReceivedPackets);
|
|
pReceivedPackets = Next;
|
|
}
|
|
|
|
pLastConsecutivePacket = 0;
|
|
ConsecutiveDataBytes = 0;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_PACKET_ENGINE::SendSomeFragments(
|
|
unsigned char PacketType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends some fragments of the user buffer.
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
result of the send operation
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
unsigned short i = 0;
|
|
unsigned short AckFragment;
|
|
unsigned short Frag;
|
|
unsigned short Remainder;
|
|
unsigned Offset;
|
|
|
|
if (!Buffer &&
|
|
(BufferFlags & RPC_BUFFER_PARTIAL))
|
|
{
|
|
return RPC_S_SEND_INCOMPLETE;
|
|
}
|
|
|
|
if (SendBurstLength > SendWindowSize)
|
|
{
|
|
SendBurstLength = SendWindowSize;
|
|
}
|
|
|
|
//
|
|
// If we can extend the window, do so; otherwise, resend old packets.
|
|
//
|
|
unsigned FragmentsSent = 0;
|
|
|
|
if (FirstUnsentFragment <= FinalSendFrag &&
|
|
FirstUnsentFragment < SendWindowBase + SendWindowSize)
|
|
{
|
|
unsigned ThisBurstLength;
|
|
|
|
Frag = FirstUnsentFragment;
|
|
|
|
ThisBurstLength = SendBurstLength;
|
|
|
|
if (ThisBurstLength > FinalSendFrag + 1 - Frag)
|
|
{
|
|
ThisBurstLength = FinalSendFrag + 1 - Frag;
|
|
}
|
|
|
|
if (Frag + ThisBurstLength > SendWindowBase + SendWindowSize)
|
|
{
|
|
ThisBurstLength = (SendWindowBase + SendWindowSize) - Frag;
|
|
}
|
|
|
|
while (++FragmentsSent <= ThisBurstLength && Status == RPC_S_OK)
|
|
{
|
|
if (FragmentsSent == ThisBurstLength &&
|
|
(Frag != FinalSendFrag || (BufferFlags & RPC_BUFFER_PARTIAL)))
|
|
{
|
|
Status = SendFragment(Frag, PacketType, TRUE);
|
|
}
|
|
else
|
|
{
|
|
Status = SendFragment(Frag, PacketType, FALSE);
|
|
}
|
|
|
|
++Frag;
|
|
}
|
|
|
|
//
|
|
// Cut down the burst length if our window is maxed out.
|
|
//
|
|
if (Frag - SendWindowBase >= SendWindowSize)
|
|
{
|
|
SendBurstLength = (1+SendBurstLength)/2;
|
|
}
|
|
|
|
if (0 == FragmentsSent && !IsBufferAcknowledged())
|
|
{
|
|
// We can get here if all the unacknowledged fragments have serial
|
|
// numbers greater than the one the client last acknowledged, and
|
|
// the window is also maxed out.
|
|
//
|
|
// This could mean the network is very slow, or the unack'ed packets
|
|
// have been lost. Since we are in SendSomePackets, let's send
|
|
// something.
|
|
//
|
|
Status = SendFragment(SendWindowBase, PacketType, TRUE);
|
|
++FragmentsSent;
|
|
}
|
|
|
|
if (Status)
|
|
{
|
|
--Frag;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsBufferAcknowledged())
|
|
{
|
|
//
|
|
// A packet seems to have been dropped. Send only one.
|
|
//
|
|
Status = SendFragment(SendWindowBase, PacketType, TRUE);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_PACKET_ENGINE::SendFragment(
|
|
unsigned FragNum,
|
|
unsigned char PacketType,
|
|
BOOL fFack
|
|
)
|
|
{
|
|
NCA_PACKET_HEADER PriorData;
|
|
UNALIGNED NCA_PACKET_HEADER __RPC_FAR * pHeader;
|
|
|
|
//
|
|
// Figure out where the packet starts and how long it is.
|
|
//
|
|
unsigned Offset;
|
|
unsigned Length;
|
|
unsigned Index = (FragNum - SendWindowBase + RingBufferBase) % MAX_WINDOW_SIZE;
|
|
unsigned DistanceToEnd;
|
|
|
|
if (FragNum < FirstUnsentFragment)
|
|
{
|
|
Offset = FragmentRingBuffer[Index].Offset;
|
|
Length = FragmentRingBuffer[Index].Length;
|
|
DistanceToEnd = BufferLength - Offset;
|
|
|
|
#ifdef DEBUGRPC
|
|
if (Offset >= 0xb000b000 || Length >= 0xd000)
|
|
{
|
|
RpcpBreakPoint();
|
|
}
|
|
#endif
|
|
fRetransmitted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FragNum == FirstUnsentFragment);
|
|
|
|
Offset = FirstUnsentOffset;
|
|
Length = MaxFragmentSize;
|
|
DistanceToEnd = BufferLength - Offset;
|
|
|
|
if (DistanceToEnd < Length)
|
|
{
|
|
//
|
|
// We want to send only full packets on a PARTIAL send, so return
|
|
// send-incomplete for the last piece.
|
|
//
|
|
if (BufferFlags & RPC_BUFFER_PARTIAL)
|
|
{
|
|
return RPC_S_SEND_INCOMPLETE;
|
|
}
|
|
|
|
Length = DistanceToEnd;
|
|
}
|
|
|
|
FirstUnsentOffset += Length;
|
|
FirstUnsentFragment = 1 + FragNum;
|
|
}
|
|
|
|
if (BufferLength)
|
|
{
|
|
ASSERT(Length);
|
|
ASSERT(Offset < BufferLength);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(!Length);
|
|
ASSERT(!Offset);
|
|
}
|
|
|
|
//
|
|
// Time to start assembling the buffer.
|
|
//
|
|
char __RPC_FAR * pBuffer = ((char __RPC_FAR *) Buffer)
|
|
+ Offset
|
|
- sizeof(NCA_PACKET_HEADER);
|
|
|
|
pHeader = (PNCA_PACKET_HEADER) pBuffer;
|
|
|
|
if (FragNum)
|
|
{
|
|
PriorData = *pHeader;
|
|
}
|
|
|
|
*pHeader = pSavedPacket->Header;
|
|
|
|
pHeader->PacketType = PacketType;
|
|
pHeader->FragmentNumber = FragNum;
|
|
pHeader->PacketFlags = RpcToPacketFlagsArray[BufferFlags & RPC_NCA_PACKET_FLAGS];
|
|
|
|
if (FinalSendFrag != 0 ||
|
|
(BufferFlags & RPC_BUFFER_PARTIAL))
|
|
{
|
|
pHeader->PacketFlags |= DG_PF_FRAG;
|
|
|
|
if (FragNum == FinalSendFrag &&
|
|
0 == (BufferFlags & RPC_BUFFER_PARTIAL))
|
|
{
|
|
pHeader->PacketFlags |= DG_PF_LAST_FRAG;
|
|
}
|
|
}
|
|
|
|
pHeader->PacketBodyLen = Length;
|
|
|
|
if (FALSE == fFack)
|
|
{
|
|
pHeader->PacketFlags |= DG_PF_NO_FACK;
|
|
}
|
|
|
|
AddSerialNumber(pHeader);
|
|
|
|
RPC_STATUS Status;
|
|
Status = SealAndSendPacket(pHeader);
|
|
|
|
FragmentRingBuffer[Index].SerialNumber = SendSerialNumber;
|
|
FragmentRingBuffer[Index].Length = Length;
|
|
FragmentRingBuffer[Index].Offset = Offset;
|
|
|
|
++SendSerialNumber;
|
|
|
|
if (FragNum)
|
|
{
|
|
*pHeader = PriorData;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET_ENGINE::UpdateSendWindow(
|
|
PDG_PACKET pPacket,
|
|
PSECURITY_CONTEXT pSecurityContext,
|
|
PDG_ASSOCIATION Association
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the send window based upon a received FACK or NOCALL.
|
|
The caller should filter out other packet types.
|
|
|
|
Arguments:
|
|
|
|
pPacket - the packet received
|
|
|
|
Return Value:
|
|
|
|
return code:
|
|
|
|
TRUE if the send needs to be reset (server crashed)
|
|
FALSE if not
|
|
--*/
|
|
{
|
|
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pPacket->Header.Data;
|
|
|
|
#ifdef MULTITHREADED
|
|
ASSERT(pPacket->TimeReceived == 0x31415926);
|
|
#endif
|
|
|
|
//
|
|
// Check that we can understand this packet.
|
|
//
|
|
if (0 != pPacket->Header.PacketBodyLen)
|
|
{
|
|
//
|
|
// Version 0 and version 1 are identical.
|
|
//
|
|
if (0 != pBody->Version &&
|
|
1 != pBody->Version)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC DG: warning - FACK body version %u\n", pBody->Version);
|
|
#endif
|
|
pPacket->Header.PacketBodyLen = 0;
|
|
}
|
|
else if (pPacket->Header.PacketBodyLen < sizeof(FACK_BODY_VER_0))
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC DG: warning - FACK body truncated\n");
|
|
#endif
|
|
pPacket->Header.PacketBodyLen = 0;
|
|
}
|
|
else if (pPacket->Header.PacketBodyLen < sizeof(FACK_BODY_VER_0) + pBody->AckWordCount * sizeof(unsigned long))
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC DG: warning - FACK body length inconsistent\n");
|
|
#endif
|
|
pPacket->Header.PacketBodyLen = 0;
|
|
}
|
|
else
|
|
{
|
|
if (NeedsByteSwap(&pPacket->Header))
|
|
{
|
|
ByteSwapFackBody0(pBody);
|
|
}
|
|
|
|
//
|
|
// NT 1057 used 0xffff to signal no packets have been received.
|
|
// This doesn't match OSF.
|
|
//
|
|
if (0xffff == pBody->SerialNumber)
|
|
{
|
|
pBody->SerialNumber = 0;
|
|
}
|
|
|
|
if (pBody->SerialNumber < FackSerialNumber)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FackSerialNumber = pBody->SerialNumber;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update send window.
|
|
//
|
|
unsigned short RemoteBase = 1+pPacket->Header.FragmentNumber;
|
|
|
|
if (RemoteBase < SendWindowBase)
|
|
{
|
|
//
|
|
// Fragments previously acknowledged are now missing. Either this
|
|
// packet was delivered out of order, or the server crashed and
|
|
// restarted. Ignore the packet.
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (RemoteBase > FirstUnsentFragment)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("RPC DG: bogus FACK packet received\n");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
//
|
|
// We are moving the window base forward. We need to advance the
|
|
// ring buffer base by the same amount, and clear the entries
|
|
// corresponding to unsent packets.
|
|
//
|
|
unsigned short Diff = RemoteBase - SendWindowBase;
|
|
|
|
ASSERT(Diff <= MAX_WINDOW_SIZE);
|
|
|
|
while (Diff)
|
|
{
|
|
FragmentRingBuffer[RingBufferBase].Length = 0;
|
|
++RingBufferBase;
|
|
RingBufferBase %= MAX_WINDOW_SIZE;
|
|
--Diff;
|
|
}
|
|
|
|
SendWindowBase = RemoteBase;
|
|
SendWindowBits = 0;
|
|
|
|
if (0 != pPacket->Header.PacketBodyLen)
|
|
{
|
|
//
|
|
// Save missing-packet bitmask.
|
|
//
|
|
SendWindowBits = pBody->Acks[0];
|
|
|
|
//
|
|
// Adjust window size.
|
|
//
|
|
if (pBody->WindowSize > MAX_WINDOW_SIZE)
|
|
{
|
|
pBody->WindowSize = MAX_WINDOW_SIZE;
|
|
}
|
|
|
|
SendWindowSize = pBody->WindowSize;
|
|
|
|
if (SendBurstLength > SendWindowSize)
|
|
{
|
|
SendBurstLength = SendWindowSize;
|
|
}
|
|
|
|
//
|
|
// Adjust maximum PDU length.
|
|
//
|
|
unsigned NewPduSize;
|
|
NewPduSize = pBody->MaxDatagramSize;
|
|
if (NewPduSize > MaxPduSize)
|
|
{
|
|
NewPduSize = MaxPduSize;
|
|
}
|
|
|
|
if (NewPduSize != CurrentPduSize)
|
|
{
|
|
NextCallPduSize = NewPduSize;
|
|
}
|
|
|
|
if (Association)
|
|
{
|
|
Association->CurrentPduSize = NewPduSize;
|
|
Association->RemoteWindowSize = SendWindowSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
DG_PACKET_ENGINE::UpdateReceiveWindow(
|
|
PDG_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a fragment to the receive list, and sends a FACK.
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
#ifdef MULTITHREADED
|
|
ASSERT(pPacket->TimeReceived == 0x31415926);
|
|
#endif
|
|
|
|
//
|
|
// Don't retain data from previous pipe buffers.
|
|
//
|
|
if (pPacket->Header.FragmentNumber < ReceiveFragmentBase)
|
|
{
|
|
if (0 == (pPacket->Header.PacketFlags & DG_PF_NO_FACK))
|
|
{
|
|
SendFack(pPacket);
|
|
}
|
|
|
|
FreePacket(pPacket);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Attempt to guess the client's max PDU size. Round down to a multiple
|
|
// of eight, for NDR.
|
|
//
|
|
if (pPacket->DataLength + sizeof(NCA_PACKET_HEADER) > NextCallPduSize)
|
|
{
|
|
NextCallPduSize = pPacket->DataLength + sizeof(NCA_PACKET_HEADER);
|
|
NextCallPduSize &= ~7;
|
|
}
|
|
|
|
PNCA_PACKET_HEADER pHeader = &pPacket->Header;
|
|
|
|
unsigned short Serial = ReadSerialNumber(pHeader);
|
|
|
|
if (Serial > ReceiveSerialNumber)
|
|
{
|
|
ReceiveSerialNumber = Serial;
|
|
}
|
|
|
|
//
|
|
// Authentication levels above AUTHN_LEVEL_PKT will checksum the packet,
|
|
// so we must remove these bits from the header.
|
|
//
|
|
pPacket->Header.PacketFlags &= ~(DG_PF_FORWARDED);
|
|
pPacket->Header.PacketFlags2 &= ~(DG_PF_FORWARDED_2);
|
|
|
|
//
|
|
// Check the easy case: is this a single packet call?
|
|
//
|
|
if ((pHeader->PacketFlags & DG_PF_FRAG) == 0 &&
|
|
(pHeader->PacketFlags & DG_PF_LAST_FRAG) == 0)
|
|
{
|
|
if (pReceivedPackets)
|
|
{
|
|
ASSERT( pReceivedPackets->Header.SequenceNumber == pPacket->Header.SequenceNumber );
|
|
FreePacket(pPacket);
|
|
return FALSE;
|
|
}
|
|
|
|
pReceivedPackets = pPacket;
|
|
pLastConsecutivePacket = pPacket;
|
|
|
|
pPacket->pNext = pPacket->pPrevious = 0;
|
|
|
|
ConsecutiveDataBytes += pHeader->PacketBodyLen;
|
|
|
|
fReceivedAllFragments = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// This is a multi-packet call. Insert the packet in pReceivedPackets
|
|
// and send a FACK.
|
|
//
|
|
PDG_PACKET pScan;
|
|
PDG_PACKET pTrail;
|
|
BOOL PacketAddedToList = TRUE;
|
|
|
|
if (pReceivedPackets == 0)
|
|
{
|
|
pReceivedPackets = pPacket;
|
|
|
|
if (ReceiveFragmentBase == pHeader->FragmentNumber)
|
|
{
|
|
pLastConsecutivePacket = pPacket;
|
|
ConsecutiveDataBytes += pHeader->PacketBodyLen;
|
|
}
|
|
|
|
pPacket->pNext = pPacket->pPrevious = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not the first packet to be received. So scan for its place in the
|
|
// list.
|
|
//
|
|
unsigned short FragNum = pHeader->FragmentNumber;
|
|
|
|
if (pLastConsecutivePacket)
|
|
{
|
|
pScan = pLastConsecutivePacket;
|
|
}
|
|
else
|
|
{
|
|
pScan = pReceivedPackets;
|
|
}
|
|
|
|
pTrail = 0;
|
|
while (pScan && pScan->Header.FragmentNumber < FragNum)
|
|
{
|
|
ASSERT(pScan->TimeReceived == 0x31415926);
|
|
ASSERT(pScan->Header.SequenceNumber == SequenceNumber);
|
|
|
|
pTrail = pScan;
|
|
pScan = pScan->pNext;
|
|
}
|
|
|
|
if (pScan != 0)
|
|
{
|
|
if (pScan->Header.FragmentNumber > FragNum)
|
|
{
|
|
if (pScan->pPrevious &&
|
|
pScan->pPrevious->Header.FragmentNumber >= FragNum)
|
|
{
|
|
//
|
|
// The new packet is a duplicate of a preexisting one
|
|
// upstream from pLastConsecutivePacket.
|
|
//
|
|
PacketAddedToList = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Our fragment fills a gap in the series.
|
|
//
|
|
pPacket->pPrevious = pScan->pPrevious;
|
|
pPacket->pNext = pScan;
|
|
|
|
if (pScan->pPrevious == 0)
|
|
{
|
|
pReceivedPackets = pPacket;
|
|
}
|
|
else
|
|
{
|
|
pScan->pPrevious->pNext = pPacket;
|
|
}
|
|
pScan->pPrevious = pPacket;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The new packet is a duplicate of a preexisting one
|
|
// downstream from pLastConsecutivePacket.
|
|
//
|
|
PacketAddedToList = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The fragnum is larger than everything seen so far.
|
|
//
|
|
pTrail->pNext = pPacket;
|
|
pPacket->pPrevious = pTrail;
|
|
pPacket->pNext = 0;
|
|
}
|
|
}
|
|
|
|
if (TRUE == PacketAddedToList)
|
|
{
|
|
//
|
|
// Scan the list for the first missing fragment.
|
|
//
|
|
unsigned short ScanNum;
|
|
if (pLastConsecutivePacket)
|
|
{
|
|
pScan = pLastConsecutivePacket->pNext;
|
|
ScanNum = pLastConsecutivePacket->Header.FragmentNumber + 1;
|
|
}
|
|
else
|
|
{
|
|
pScan = pReceivedPackets;
|
|
ScanNum = ReceiveFragmentBase;
|
|
}
|
|
|
|
while (pScan)
|
|
{
|
|
if (ScanNum == pScan->Header.FragmentNumber)
|
|
{
|
|
ConsecutiveDataBytes += pScan->Header.PacketBodyLen;
|
|
pLastConsecutivePacket = pScan;
|
|
}
|
|
|
|
pScan = pScan->pNext;
|
|
++ScanNum;
|
|
}
|
|
|
|
//
|
|
// We have updated pLastConsecutivePacket; is the whole buffer here?
|
|
//
|
|
if (pLastConsecutivePacket &&
|
|
pLastConsecutivePacket->Header.PacketFlags & DG_PF_LAST_FRAG)
|
|
{
|
|
fReceivedAllFragments = TRUE;
|
|
}
|
|
}
|
|
|
|
ASSERT(pReceivedPackets);
|
|
|
|
//
|
|
// Fack the fragment if necessary.
|
|
//
|
|
if (0 == (pHeader->PacketFlags & DG_PF_NO_FACK))
|
|
{
|
|
SendFack(pPacket);
|
|
}
|
|
|
|
if (FALSE == PacketAddedToList)
|
|
{
|
|
FreePacket(pPacket);
|
|
}
|
|
|
|
return PacketAddedToList;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_PACKET_ENGINE::SendFack(
|
|
PDG_PACKET pPacket
|
|
)
|
|
{
|
|
pSavedPacket->Header.PacketType = DG_FACK;
|
|
pSavedPacket->Header.SequenceNumber = SequenceNumber;
|
|
|
|
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pSavedPacket->Header.Data;
|
|
|
|
pBody->Version = 1;
|
|
pBody->Pad1 = 0;
|
|
pBody->WindowSize = ReceiveWindowSize;
|
|
pBody->MaxDatagramSize = MaxPduSize;
|
|
pBody->MaxPacketSize = MaxPacketSize;
|
|
pBody->AckWordCount = 1;
|
|
|
|
if (pPacket)
|
|
{
|
|
pBody->SerialNumber = ReadSerialNumber(&pPacket->Header);
|
|
}
|
|
else
|
|
{
|
|
pBody->SerialNumber = ReceiveSerialNumber;
|
|
}
|
|
|
|
unsigned short FragNum = ReceiveFragmentBase-1;
|
|
PDG_PACKET pScan = 0;
|
|
|
|
if (pLastConsecutivePacket)
|
|
{
|
|
FragNum = pLastConsecutivePacket->Header.FragmentNumber;
|
|
pScan = pLastConsecutivePacket->pNext;
|
|
}
|
|
else if (pReceivedPackets)
|
|
{
|
|
pScan = pReceivedPackets->pNext;
|
|
}
|
|
|
|
pSavedPacket->Header.FragmentNumber = FragNum;
|
|
|
|
unsigned Bit;
|
|
pBody->Acks[0] = 0;
|
|
|
|
while ( pScan )
|
|
{
|
|
Bit = pScan->Header.FragmentNumber - FragNum - 1;
|
|
|
|
pBody->Acks[0] |= (1 << Bit);
|
|
|
|
pScan = pScan->pNext;
|
|
}
|
|
|
|
if (pBody->Acks[0] == 0)
|
|
{
|
|
pBody->AckWordCount = 0;
|
|
}
|
|
|
|
pSavedPacket->Header.PacketBodyLen = sizeof(FACK_BODY_VER_0) + sizeof(unsigned long);
|
|
|
|
AddSerialNumber(&pSavedPacket->Header);
|
|
|
|
return SealAndSendPacket(&pSavedPacket->Header);
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
DG_PACKET_ENGINE::AssembleBufferFromPackets(
|
|
PRPC_MESSAGE Message,
|
|
CONNECTION * pConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function coalesces the list of consecutive packets into a monolithic
|
|
buffer.
|
|
|
|
Arguments:
|
|
|
|
Message - if .Buffer != 0 , use it. Otherwise allocate one.
|
|
|
|
pConnection - a connection in case we need to call GetBuffer
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK - success
|
|
|
|
RPC_S_OUT_OF_MEMORY - we couldn't allocate or reallocate Message.Buffer
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(pLastConsecutivePacket);
|
|
|
|
//
|
|
// If only one packet is available, use the packet buffer itself.
|
|
//
|
|
if (0 == Message->Buffer && 0 == pReceivedPackets->pNext)
|
|
{
|
|
ASSERT(ConsecutiveDataBytes == pReceivedPackets->Header.PacketBodyLen);
|
|
|
|
Message->Buffer = pReceivedPackets->Header.Data;
|
|
Message->BufferLength = ConsecutiveDataBytes;
|
|
Message->DataRepresentation = 0x00ffffff & (*(unsigned long PAPI *) &pReceivedPackets->Header.DataRep);
|
|
|
|
if (0 == (pReceivedPackets->Header.PacketFlags & DG_PF_FRAG))
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE;
|
|
}
|
|
|
|
if (pReceivedPackets->Header.PacketFlags & DG_PF_LAST_FRAG)
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE;
|
|
}
|
|
|
|
pReceivedPackets = 0;
|
|
pLastConsecutivePacket = 0;
|
|
|
|
ConsecutiveDataBytes = 0;
|
|
|
|
++ReceiveFragmentBase;
|
|
|
|
LastReceiveBuffer = Message->Buffer;
|
|
LastReceiveBufferLength = Message->BufferLength;
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
//
|
|
// Get a buffer if we need it.
|
|
//
|
|
RPC_STATUS Status;
|
|
|
|
if (0 == Message->Buffer)
|
|
{
|
|
ASSERT(0 == (Message->RpcFlags & RPC_BUFFER_EXTRA));
|
|
|
|
Message->BufferLength = ConsecutiveDataBytes;
|
|
|
|
Status = pConnection->GetBuffer(Message);
|
|
if (RPC_S_OK != Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
LastReceiveBuffer = Message->Buffer;
|
|
LastReceiveBufferLength = Message->BufferLength;
|
|
}
|
|
|
|
//
|
|
// Reallocate the buffer if it is too small.
|
|
//
|
|
char __RPC_FAR * CopyBuffer = (char __RPC_FAR *) Message->Buffer;
|
|
|
|
if (Message->RpcFlags & (RPC_BUFFER_EXTRA | RPC_BUFFER_PARTIAL))
|
|
{
|
|
ASSERT( !LastReceiveBufferLength ||
|
|
(CopyBuffer >= LastReceiveBuffer &&
|
|
CopyBuffer <= ((char __RPC_FAR *) LastReceiveBuffer) + LastReceiveBufferLength) );
|
|
|
|
if (0 == (Message->RpcFlags & RPC_BUFFER_EXTRA))
|
|
{
|
|
Message->BufferLength = 0;
|
|
}
|
|
|
|
unsigned Offset = Message->BufferLength;
|
|
CopyBuffer += Offset;
|
|
if (CopyBuffer + ConsecutiveDataBytes > ((char __RPC_FAR *) LastReceiveBuffer) + LastReceiveBufferLength)
|
|
{
|
|
Status = I_RpcReallocPipeBuffer(Message, Offset + ConsecutiveDataBytes);
|
|
if (RPC_S_OK != Status)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
CopyBuffer = (char __RPC_FAR *) Message->Buffer + Offset;
|
|
}
|
|
else
|
|
{
|
|
Message->BufferLength += ConsecutiveDataBytes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Message->BufferLength = ConsecutiveDataBytes;
|
|
}
|
|
|
|
Message->DataRepresentation = 0x00ffffff & (*(unsigned long PAPI *) &pReceivedPackets->Header.DataRep);
|
|
|
|
{
|
|
PDG_PACKET pkt = DG_PACKET::ContainingRecord(Message->Buffer);
|
|
|
|
ASSERT( pkt->MaxDataLength >= Message->BufferLength );
|
|
}
|
|
|
|
//
|
|
// Copy the stub data into the buffer.
|
|
//
|
|
#ifdef DEBUGRPC
|
|
unsigned long Count = 0;
|
|
#endif
|
|
|
|
PDG_PACKET Packet;
|
|
BOOL fLastPacket = FALSE;
|
|
do
|
|
{
|
|
ASSERT(pReceivedPackets->TimeReceived == 0x31415926);
|
|
ASSERT(ReceiveFragmentBase == pReceivedPackets->Header.FragmentNumber);
|
|
|
|
if (pReceivedPackets == pLastConsecutivePacket)
|
|
{
|
|
fLastPacket = TRUE;
|
|
|
|
if (0 == (pReceivedPackets->Header.PacketFlags & DG_PF_FRAG))
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE;
|
|
}
|
|
|
|
if (pReceivedPackets->Header.PacketFlags & DG_PF_LAST_FRAG)
|
|
{
|
|
Message->RpcFlags |= RPC_BUFFER_COMPLETE;
|
|
}
|
|
}
|
|
|
|
unsigned Length = pReceivedPackets->Header.PacketBodyLen;
|
|
RpcpMemoryCopy(CopyBuffer, pReceivedPackets->Header.Data, Length);
|
|
|
|
#ifdef DEBUGRPC
|
|
Count += Length;
|
|
#endif
|
|
|
|
CopyBuffer += Length;
|
|
Packet = pReceivedPackets;
|
|
|
|
pReceivedPackets = pReceivedPackets->pNext;
|
|
ASSERT(!pReceivedPackets || pReceivedPackets->pPrevious == Packet);
|
|
FreePacket(Packet);
|
|
|
|
++ReceiveFragmentBase;
|
|
}
|
|
while (!fLastPacket);
|
|
|
|
ASSERT(Count == ConsecutiveDataBytes);
|
|
|
|
ASSERT(fLastPacket || 0 == Count % 8);
|
|
|
|
pLastConsecutivePacket = 0;
|
|
ConsecutiveDataBytes = 0;
|
|
|
|
if (pReceivedPackets)
|
|
{
|
|
pReceivedPackets->pPrevious = 0;
|
|
}
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
RPC_STATUS
|
|
VerifySecurePacket(
|
|
PDG_PACKET pPacket,
|
|
SECURITY_CONTEXT * pSecurityContext
|
|
)
|
|
{
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
PDG_SECURITY_TRAILER pVerifier = (PDG_SECURITY_TRAILER)
|
|
(pPacket->Header.Data + pPacket->Header.PacketBodyLen);
|
|
|
|
if (pSecurityContext->AuthenticationLevel < RPC_C_AUTHN_LEVEL_PKT)
|
|
{
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
ASSERT(pVerifier->protection_level >= RPC_C_AUTHN_LEVEL_PKT);
|
|
ASSERT(pVerifier->protection_level <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
|
|
|
|
SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
|
|
SECURITY_BUFFER SecurityBuffers[5];
|
|
DCE_MSG_SECURITY_INFO MsgSecurityInfo;
|
|
|
|
BufferDescriptor.ulVersion = 0;
|
|
BufferDescriptor.cBuffers = 5;
|
|
BufferDescriptor.pBuffers = SecurityBuffers;
|
|
|
|
SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[0].pvBuffer = &pPacket->Header;
|
|
SecurityBuffers[0].cbBuffer = sizeof(NCA_PACKET_HEADER);
|
|
|
|
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
|
|
SecurityBuffers[1].pvBuffer = pPacket->Header.Data;
|
|
SecurityBuffers[1].cbBuffer = pPacket->Header.PacketBodyLen;
|
|
|
|
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
|
SecurityBuffers[2].pvBuffer = pVerifier;
|
|
|
|
if (pVerifier->protection_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
|
{
|
|
unsigned Alignment = Align4(pSecurityContext->BlockSize());
|
|
|
|
SecurityBuffers[2].cbBuffer = Align(sizeof(DG_SECURITY_TRAILER), Alignment);
|
|
SecurityBuffers[3].pvBuffer = Align(pVerifier + 1, Alignment);
|
|
}
|
|
else
|
|
{
|
|
SecurityBuffers[2].cbBuffer = Align4(sizeof(DG_SECURITY_TRAILER));
|
|
SecurityBuffers[3].pvBuffer = Align4(pVerifier + 1);
|
|
}
|
|
|
|
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
|
|
SecurityBuffers[3].cbBuffer = pPacket->DataLength
|
|
- SecurityBuffers[1].cbBuffer
|
|
- SecurityBuffers[2].cbBuffer;
|
|
|
|
SecurityBuffers[4].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
|
|
SecurityBuffers[4].pvBuffer = &MsgSecurityInfo;
|
|
SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
|
|
|
|
MsgSecurityInfo.SendSequenceNumber = pPacket->Header.FragmentNumber;
|
|
MsgSecurityInfo.ReceiveSequenceNumber = pSecurityContext->AuthContextId;
|
|
MsgSecurityInfo.PacketType = ~0;
|
|
|
|
//
|
|
// If the packet came from a big-endian machine, we must restore
|
|
// the header to its original condition or the checksum will fail.
|
|
//
|
|
ByteSwapPacketHeaderIfNecessary(pPacket);
|
|
|
|
Status = pSecurityContext->VerifyOrUnseal(
|
|
pPacket->Header.SequenceNumber,
|
|
pVerifier->protection_level != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
&BufferDescriptor
|
|
);
|
|
|
|
//
|
|
// Gotta re-swap the header so we can still look at its fields.
|
|
//
|
|
ByteSwapPacketHeaderIfNecessary(pPacket);
|
|
|
|
if (RPC_S_OK != Status)
|
|
{
|
|
ASSERT(Status == RPC_S_ACCESS_DENIED);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET_ENGINE::SetFragmentLengths(
|
|
PSECURITY_CONTEXT pSecurityContext
|
|
)
|
|
{
|
|
if (0 == pSecurityContext)
|
|
{
|
|
SecurityTrailerSize = 0;
|
|
}
|
|
else switch (pSecurityContext->AuthenticationLevel)
|
|
{
|
|
case RPC_C_AUTHN_LEVEL_NONE:
|
|
{
|
|
SecurityTrailerSize = 0;
|
|
break;
|
|
}
|
|
|
|
case RPC_C_AUTHN_LEVEL_PKT:
|
|
case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
|
|
{
|
|
SecurityTrailerSize = pSecurityContext->MaximumSignatureLength();
|
|
SecurityTrailerSize += Align4(sizeof(DG_SECURITY_TRAILER));
|
|
break;
|
|
}
|
|
|
|
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
|
{
|
|
SecurityTrailerSize = pSecurityContext->MaximumHeaderLength();
|
|
SecurityTrailerSize += Align(sizeof(DG_SECURITY_TRAILER), Align4(pSecurityContext->BlockSize()));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERT(0 && "RPC: unknown protect level");
|
|
break;
|
|
}
|
|
}
|
|
|
|
RecalcFragmentSize();
|
|
}
|
|
|
|
|
|
void
|
|
ByteSwapPacketHeader(
|
|
PDG_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Byte swaps the packet header of the specified packet.
|
|
|
|
Arguments:
|
|
|
|
pPacket - Pointer to the packet whose header needs byte swapping.
|
|
|
|
Return Value:
|
|
|
|
<none>
|
|
|
|
--*/
|
|
{
|
|
unsigned long __RPC_FAR * VerNum = (unsigned long __RPC_FAR *) &(pPacket->Header.InterfaceVersion);
|
|
|
|
ByteSwapUuid(&(pPacket->Header.ObjectId));
|
|
ByteSwapUuid(&(pPacket->Header.InterfaceId));
|
|
ByteSwapUuid(&(pPacket->Header.ActivityId));
|
|
ByteSwapLong(pPacket->Header.ServerBootTime);
|
|
ByteSwapLong(*VerNum);
|
|
ByteSwapLong(pPacket->Header.SequenceNumber);
|
|
ByteSwapShort(pPacket->Header.OperationNumber);
|
|
ByteSwapShort(pPacket->Header.InterfaceHint);
|
|
ByteSwapShort(pPacket->Header.ActivityHint);
|
|
ByteSwapShort(pPacket->Header.PacketBodyLen);
|
|
ByteSwapShort(pPacket->Header.FragmentNumber);
|
|
}
|
|
|
|
|
|
void
|
|
ByteSwapFackBody0(
|
|
FACK_BODY_VER_0 __RPC_FAR * pBody
|
|
)
|
|
{
|
|
ByteSwapShort(pBody->WindowSize);
|
|
ByteSwapLong (pBody->MaxDatagramSize);
|
|
ByteSwapLong (pBody->MaxPacketSize);
|
|
ByteSwapShort(pBody->SerialNumber);
|
|
ByteSwapShort(pBody->AckWordCount);
|
|
|
|
unsigned u;
|
|
for (u=0; u < pBody->AckWordCount; ++u)
|
|
{
|
|
ByteSwapLong (pBody->Acks[u]);
|
|
}
|
|
}
|
|
|
|
MUTEX * DG_PACKET::PacketListMutex;
|
|
|
|
DG_PACKET::PACKET_LIST DG_PACKET::PacketLists[DG_PACKET::NUMBER_OF_PACKET_LISTS];
|
|
|
|
RPC_STATUS
|
|
DG_PACKET::Initialize(
|
|
)
|
|
{
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
|
|
PacketListMutex = new MUTEX(&Status);
|
|
|
|
if (!PacketListMutex)
|
|
{
|
|
return RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
PDG_PACKET
|
|
DG_PACKET::AllocatePacket(
|
|
unsigned BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a DG_PACKET with the specified buffer size.
|
|
|
|
Arguments:
|
|
|
|
ObjectSize - generated by compiler; same as sizeof(DG_PACKET)
|
|
|
|
BufferLength - actual packet size
|
|
|
|
Return Value:
|
|
|
|
an 8-byte-aligned pointer to an obect of the requested size
|
|
|
|
--*/
|
|
|
|
{
|
|
PDG_PACKET Packet = 0;
|
|
unsigned i;
|
|
|
|
i = 0;
|
|
while (PacketLists[i].PacketLength != BufferLength &&
|
|
i < NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
++i;
|
|
}
|
|
|
|
if (i != NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
//
|
|
// We found an existing packet list.
|
|
//
|
|
PacketListMutex->Request();
|
|
|
|
if (PacketLists[i].Count)
|
|
{
|
|
Packet = PacketLists[i].Head;
|
|
PacketLists[i].Head = PacketLists[i].Head->pNext;
|
|
PacketLists[i].Count--;
|
|
|
|
ASSERT( Packet->MaxDataLength == BufferLength );
|
|
}
|
|
|
|
PacketListMutex->Clear();
|
|
}
|
|
|
|
if (!Packet)
|
|
{
|
|
Packet = new (BufferLength) DG_PACKET(BufferLength);
|
|
}
|
|
|
|
#ifdef MULTITHREADED
|
|
#if defined(DEBUGRPC)
|
|
|
|
if (Packet)
|
|
{
|
|
Packet->TimeReceived = 0x31415926;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
PacketListMutex->VerifyNotOwned();
|
|
|
|
return Packet;
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET::FreePacket(
|
|
PDG_PACKET Packet
|
|
)
|
|
{
|
|
unsigned i;
|
|
|
|
#ifdef MULTITHREADED
|
|
|
|
ASSERT(Packet->TimeReceived == 0x31415926);
|
|
|
|
Packet->TimeReceived = CurrentTimeInMsec();
|
|
#endif
|
|
|
|
i = 0;
|
|
while (PacketLists[i].PacketLength != Packet->MaxDataLength &&
|
|
i < NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
++i;
|
|
}
|
|
|
|
if (i != NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
//
|
|
// We found an existing packet list.
|
|
//
|
|
PacketListMutex->Request();
|
|
|
|
#ifdef DEBUGRPC
|
|
PDG_PACKET pkt;
|
|
unsigned Count;
|
|
|
|
for (pkt = PacketLists[i].Head, Count = 0;
|
|
pkt;
|
|
pkt = pkt->pNext)
|
|
{
|
|
ASSERT(Packet != pkt);
|
|
ASSERT(pkt != pkt->pNext);
|
|
++Count;
|
|
}
|
|
|
|
ASSERT(Count == PacketLists[i].Count);
|
|
#endif
|
|
|
|
if (PacketLists[i].Count < MAX_FREE_PACKETS)
|
|
{
|
|
Packet->pNext = PacketLists[i].Head;
|
|
PacketLists[i].Head = Packet;
|
|
PacketLists[i].Count++;
|
|
|
|
PacketListMutex->Clear();
|
|
|
|
#ifdef MULTITHREADED
|
|
DelayedActions->Add(GlobalScavengerTimer, ONE_MINUTE_IN_MSEC, FALSE);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
PacketListMutex->Clear();
|
|
|
|
delete Packet;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Arrival here means there is no list for this packet size.
|
|
//
|
|
PacketListMutex->Request();
|
|
|
|
i = 0;
|
|
while (PacketLists[i].PacketLength != 0 &&
|
|
i < NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
++i;
|
|
}
|
|
|
|
if (i != NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
//
|
|
// There is space to create another packet list.
|
|
//
|
|
PacketLists[i].PacketLength = Packet->MaxDataLength;
|
|
PacketLists[i].Head = Packet;
|
|
PacketLists[i].Count = 1;
|
|
|
|
Packet->pNext = 0;
|
|
|
|
PacketListMutex->Clear();
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Arrival here means no list exists for this packet size, and none
|
|
// could be created.
|
|
//
|
|
PacketListMutex->Clear();
|
|
delete Packet;
|
|
}
|
|
|
|
|
|
void
|
|
DG_PACKET::FlushPacketLists(
|
|
)
|
|
{
|
|
unsigned i;
|
|
|
|
#ifdef MAJORDEBUG
|
|
DbgPrint("flushing packet list\n");
|
|
#endif
|
|
|
|
PacketListMutex->Request();
|
|
|
|
i = 0;
|
|
while (i < NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
while (PacketLists[i].Head)
|
|
{
|
|
PDG_PACKET Packet = PacketLists[i].Head;
|
|
delete PacketLists[i].Head;
|
|
PacketLists[i].Head = Packet;
|
|
#ifdef DEBUGRPC
|
|
PacketLists[i].Count--;
|
|
#endif
|
|
}
|
|
|
|
ASSERT(PacketLists[i].Count == 0);
|
|
|
|
PacketLists[i].Count = 0;
|
|
|
|
++i;
|
|
}
|
|
|
|
PacketListMutex->Clear();
|
|
}
|
|
|
|
#ifdef MULTITHREADED
|
|
|
|
|
|
unsigned
|
|
DG_PACKET::ScavengePackets(
|
|
unsigned Age
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This fn scans the free packet list for very old packets and deletes them.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
unsigned i;
|
|
|
|
#ifdef MAJORDEBUG
|
|
DbgPrint("packet scavenger\n");
|
|
#endif
|
|
i = 0;
|
|
while (i < NUMBER_OF_PACKET_LISTS)
|
|
{
|
|
unsigned CutoffTime = CurrentTimeInMsec() - Age;
|
|
unsigned Count = 0;
|
|
|
|
PacketListMutex->Request();
|
|
|
|
PDG_PACKET pkt;
|
|
for (pkt = PacketLists[i].Head; pkt != NULL; pkt=pkt->pNext)
|
|
{
|
|
++Count;
|
|
if (Count >= MIN_FREE_PACKETS && pkt->TimeReceived < CutoffTime)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pkt)
|
|
{
|
|
PDG_PACKET Next = pkt->pNext;
|
|
pkt->pNext = 0;
|
|
PacketLists[i].Count = Count;
|
|
pkt = Next;
|
|
}
|
|
|
|
PacketListMutex->Clear();
|
|
|
|
while (pkt)
|
|
{
|
|
ASSERT(pkt->TimeReceived != 0x31415926);
|
|
|
|
PDG_PACKET next = pkt->pNext;
|
|
delete pkt;
|
|
pkt = next;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|