2192 lines
56 KiB
C++
2192 lines
56 KiB
C++
//+-------------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
//
|
||
// Copyright (C) Microsoft Corporation, 1994 - 1999
|
||
//
|
||
// File: dgpkt.cxx
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
/*++
|
||
|
||
Module Name:
|
||
|
||
dgpkt.cxx
|
||
|
||
Abstract:
|
||
|
||
|
||
|
||
Author:
|
||
|
||
Jeff Roberts (jroberts) 22-May-1995
|
||
|
||
Revision History:
|
||
|
||
22-May-1995 jroberts
|
||
|
||
Created this module.
|
||
|
||
09-Jul-1997 edwardr
|
||
|
||
Added support for large packets (>65535) for Falcon/RPC.
|
||
|
||
--*/
|
||
|
||
#include <precomp.hxx>
|
||
#include <dgpkt.hxx>
|
||
|
||
unsigned long ProcessStartTime;
|
||
unsigned RandomCounter = 0x6789abce;
|
||
|
||
|
||
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 char a_PacketType,
|
||
DG_PACKET * a_Packet,
|
||
RPC_STATUS * pStatus
|
||
) :
|
||
pSavedPacket (a_Packet),
|
||
PacketType (a_PacketType),
|
||
ReferenceCount (0),
|
||
BaseConnection (0),
|
||
SourceEndpoint (0),
|
||
RemoteAddress (0),
|
||
Buffer (0),
|
||
BufferLength (0),
|
||
QueuedBufferHead (0),
|
||
QueuedBufferTail (0),
|
||
pReceivedPackets (0),
|
||
pLastConsecutivePacket(0),
|
||
ConsecutiveDataBytes (0),
|
||
ReceiveFragmentBase (0),
|
||
CachedPacket (0),
|
||
LastReceiveBuffer (0),
|
||
LastReceiveBufferLength(0),
|
||
|
||
Cancelled (FALSE)
|
||
|
||
{
|
||
if (!a_Packet)
|
||
{
|
||
*pStatus = RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
if (*pStatus)
|
||
{
|
||
return;
|
||
}
|
||
|
||
pSavedPacket->Header.RpcVersion = DG_RPC_PROTOCOL_VERSION;
|
||
pSavedPacket->Header.PacketFlags = 0;
|
||
|
||
SetMyDataRep(&pSavedPacket->Header);
|
||
|
||
#ifdef DEBUGRPC
|
||
BasePacketFlags = ~0;
|
||
#endif
|
||
}
|
||
|
||
void
|
||
DG_PACKET_ENGINE::ReadConnectionInfo(
|
||
DG_COMMON_CONNECTION * a_Connection,
|
||
DG_TRANSPORT_ADDRESS a_RemoteAddress
|
||
)
|
||
{
|
||
BaseConnection = a_Connection;
|
||
RemoteAddress = a_RemoteAddress;
|
||
|
||
CurrentPduSize = 0;
|
||
SetFragmentLengths();
|
||
|
||
pSavedPacket->Header.InterfaceHint = 0xffff;
|
||
RpcpMemoryCopy( &pSavedPacket->Header.ActivityId,
|
||
&a_Connection->ActivityNode.Uuid,
|
||
sizeof(UUID)
|
||
);
|
||
}
|
||
|
||
DG_PACKET_ENGINE::~DG_PACKET_ENGINE(
|
||
)
|
||
{
|
||
ASSERT( !LastReceiveBuffer );
|
||
ASSERT( !pReceivedPackets );
|
||
ASSERT( !QueuedBufferHead );
|
||
ASSERT( !Buffer );
|
||
|
||
if (pSavedPacket)
|
||
{
|
||
FreePacket(pSavedPacket);
|
||
}
|
||
|
||
if (CachedPacket)
|
||
{
|
||
FreePacket(CachedPacket);
|
||
}
|
||
|
||
CleanupReceiveWindow();
|
||
}
|
||
|
||
|
||
void
|
||
DG_PACKET_ENGINE::NewCall()
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A new call dawns.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERT( !pLastConsecutivePacket );
|
||
ASSERT( !ConsecutiveDataBytes );
|
||
|
||
ASSERT( !LastReceiveBuffer );
|
||
|
||
SetFragmentLengths();
|
||
|
||
Buffer = 0;
|
||
|
||
fReceivedAllFragments = FALSE;
|
||
fRetransmitted = FALSE;
|
||
|
||
TimeoutCount = 0;
|
||
|
||
RepeatedFack = 0;
|
||
FackSerialNumber = 0;
|
||
SendSerialNumber = 0;
|
||
ReceiveSerialNumber = 0;
|
||
|
||
SendWindowBase = 0;
|
||
FirstUnsentFragment = 0;
|
||
SendBurstLength = SendWindowSize;
|
||
|
||
ReceiveFragmentBase = 0;
|
||
|
||
RingBufferBase = 0;
|
||
|
||
#ifdef DEBUGRPC
|
||
|
||
for (unsigned i=0; i < MAX_WINDOW_SIZE; i++)
|
||
{
|
||
FragmentRingBuffer[i].SerialNumber = 0xeeee0000;
|
||
FragmentRingBuffer[i].Length = 0xdd000000;
|
||
FragmentRingBuffer[i].Offset = 0xb000b000;
|
||
}
|
||
|
||
#endif
|
||
|
||
BasePacketFlags2 = 0;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::PushBuffer(
|
||
PRPC_MESSAGE Message
|
||
)
|
||
/*++
|
||
|
||
Function Description:
|
||
|
||
Submits a buffer to be sent over the network.
|
||
If a buffer is in progress, the new buffer is added to the
|
||
"pending" list. IF not, the buffer is placed in the "active" slot.
|
||
|
||
The only time a buffer will not go in the active slot is during an
|
||
async pipe call when the app is not waiting for send-complete
|
||
notifications before submitting new buffers.
|
||
|
||
Notes:
|
||
|
||
The buffer sent will be truncated to the nearest packet if
|
||
RPC_BUFFER_PARTIAL is set, and Message.BufferLength is set to
|
||
the amount actually sent.
|
||
|
||
--*/
|
||
{
|
||
// ASSERT( Buffer == 0 || IsBufferAcknowledged() );
|
||
|
||
RPC_STATUS Status = 0;
|
||
RPC_STATUS FixupStatus = 0;
|
||
unsigned FractionalPart = Message->BufferLength % MaxFragmentSize;
|
||
unsigned SendLength = Message->BufferLength;
|
||
|
||
if (Message->RpcFlags & RPC_BUFFER_PARTIAL)
|
||
{
|
||
SendLength -= FractionalPart;
|
||
}
|
||
|
||
if (!Buffer || IsBufferAcknowledged())
|
||
{
|
||
SetCurrentBuffer(Message->Buffer,
|
||
SendLength,
|
||
Message->RpcFlags
|
||
);
|
||
|
||
Status = SendSomeFragments();
|
||
}
|
||
else
|
||
{
|
||
QUEUED_BUFFER * Node = new QUEUED_BUFFER;
|
||
if (!Node)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
Node->Buffer = Message->Buffer;
|
||
Node->BufferLength = SendLength;
|
||
Node->BufferFlags = Message->RpcFlags;
|
||
Node->Next = 0;
|
||
|
||
if (QueuedBufferTail)
|
||
{
|
||
QueuedBufferTail->Next = Node;
|
||
}
|
||
else
|
||
{
|
||
ASSERT( !QueuedBufferHead );
|
||
|
||
QueuedBufferHead = Node;
|
||
}
|
||
|
||
QueuedBufferTail = Node;
|
||
|
||
Status = 0;
|
||
}
|
||
|
||
FixupStatus = FixupPartialSend(Message);
|
||
|
||
if (!Status)
|
||
{
|
||
Status = FixupStatus;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::PopBuffer(
|
||
BOOL fSend
|
||
)
|
||
/*++
|
||
|
||
Function Description:
|
||
|
||
Move the next pending send buffer into the active send buffer slot.
|
||
This is a no-op except unless this is an async pipe call and the app
|
||
is not waiting for send-complete notifications.
|
||
|
||
Notes:
|
||
|
||
The buffer sent will be truncated to the nearest packet if
|
||
RPC_BUFFER_PARTIAL is set, and Message.BufferLength is set to
|
||
the amount actually sent.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = 0;
|
||
RPC_MESSAGE Message;
|
||
|
||
Message.Buffer = Buffer;
|
||
Message.BufferLength = BufferLength;
|
||
|
||
QUEUED_BUFFER * Node = QueuedBufferHead;
|
||
|
||
if (Node)
|
||
{
|
||
QueuedBufferHead = Node->Next;
|
||
if (!QueuedBufferHead)
|
||
{
|
||
QueuedBufferTail = 0;
|
||
}
|
||
|
||
SetCurrentBuffer(Node->Buffer, Node->BufferLength, Node->BufferFlags);
|
||
if (fSend)
|
||
{
|
||
Status = SendSomeFragments();
|
||
}
|
||
delete Node;
|
||
}
|
||
else
|
||
{
|
||
Buffer = 0;
|
||
BufferLength = 0;
|
||
BufferFlags = 0;
|
||
}
|
||
|
||
if (Message.Buffer)
|
||
{
|
||
CommonFreeBuffer(&Message);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::FixupPartialSend(
|
||
RPC_MESSAGE * Message
|
||
)
|
||
/*++
|
||
|
||
Function Description:
|
||
|
||
This fn "does the right thing" with the unsent bit at the end of
|
||
a pipe send. For sync sends, this means moving the unsent bit
|
||
to the front of the existing buffer. For async sends, this means
|
||
allocating a new buffer and copying the unsent bit into it.
|
||
|
||
--*/
|
||
{
|
||
if (!(Message->RpcFlags & RPC_BUFFER_PARTIAL))
|
||
{
|
||
// We need this so Receive will be passed a null buffer
|
||
// unless the stub sticks one in the message.
|
||
|
||
Message->Buffer = 0;
|
||
Message->BufferLength = 0;
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
unsigned FractionalPart;
|
||
|
||
// if (Message->RpcFlags & RPC_BUFFER_ASYNC)
|
||
// {
|
||
RPC_MESSAGE NewMessage;
|
||
|
||
FractionalPart = Message->BufferLength % MaxFragmentSize;
|
||
if (!FractionalPart)
|
||
{
|
||
Message->Buffer = 0;
|
||
Message->BufferLength = 0;
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
DG_PACKET * Packet = DG_PACKET::AllocatePacket(CurrentPduSize);
|
||
if (!Packet)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
RpcpMemoryCopy(Packet->Header.Data,
|
||
((char *) Message->Buffer) + (Message->BufferLength - FractionalPart),
|
||
FractionalPart
|
||
);
|
||
|
||
Message->Buffer = Packet->Header.Data;
|
||
Message->BufferLength = FractionalPart;
|
||
// }
|
||
// else
|
||
// {
|
||
// char * Temp = (char *) Message->Buffer;
|
||
//
|
||
// FractionalPart = Message->BufferLength - FirstUnsentOffset;
|
||
// if (!FractionalPart)
|
||
// {
|
||
// return RPC_S_OK;
|
||
// }
|
||
//
|
||
// RpcpMemoryMove(Message->Buffer, Temp + FirstUnsentOffset, FractionalPart);
|
||
// Message->BufferLength = FractionalPart;
|
||
// }
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
void
|
||
DG_PACKET_ENGINE::SetCurrentBuffer(
|
||
void * a_Buffer,
|
||
unsigned a_BufferLength,
|
||
unsigned long a_BufferFlags
|
||
)
|
||
{
|
||
Buffer = a_Buffer;
|
||
BufferLength = a_BufferLength;
|
||
BufferFlags = a_BufferFlags;
|
||
|
||
TimeoutCount = 0;
|
||
SendWindowBits = 0;
|
||
FirstUnsentOffset = 0;
|
||
|
||
if (BufferLength == 0)
|
||
{
|
||
FinalSendFrag = SendWindowBase;
|
||
}
|
||
else
|
||
{
|
||
FinalSendFrag = SendWindowBase + (BufferLength-1) / MaxFragmentSize;
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::CommonGetBuffer(
|
||
RPC_MESSAGE * Message
|
||
)
|
||
{
|
||
unsigned char SubjectType;
|
||
void * Subject;
|
||
|
||
unsigned Length;
|
||
PDG_PACKET pPacket;
|
||
|
||
Length = sizeof(NCA_PACKET_HEADER)
|
||
+ Align8(Message->BufferLength)
|
||
+ SecurityTrailerSize;
|
||
|
||
unsigned BaseLength = BaseConnection->TransportInterface->BasePduSize;
|
||
|
||
// if (Length <= BaseLength)
|
||
// {
|
||
// pPacket = DG_PACKET::AllocatePacket(BaseLength);
|
||
// }
|
||
// else if (Length <= CurrentPduSize)
|
||
// {
|
||
// pPacket = AllocatePacket();
|
||
// }
|
||
// else
|
||
{
|
||
pPacket = DG_PACKET::AllocatePacket(Length);
|
||
}
|
||
|
||
if (0 == pPacket)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
//
|
||
// Point the buffer at the appropriate place in the packet.
|
||
//
|
||
Message->Buffer = pPacket->Header.Data;
|
||
|
||
// if (pPacket->MaxDataLength < 256)
|
||
// {
|
||
// AddActivePacket(pPacket);
|
||
// }
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
void
|
||
DG_PACKET_ENGINE::CommonFreeBuffer(
|
||
RPC_MESSAGE * Message
|
||
)
|
||
{
|
||
if (!Message->Buffer)
|
||
{
|
||
return;
|
||
}
|
||
|
||
PDG_PACKET Packet = DG_PACKET::FromStubData(Message->Buffer);
|
||
|
||
LogEvent(SU_ENGINE, EV_PROC, this, Message->Buffer, 'F' + (('B' + (('u' + ('f' << 8)) << 8)) << 8));
|
||
|
||
ASSERT( Packet->MaxDataLength < 0x7fffffffUL );
|
||
|
||
// if (Packet && Packet->MaxDataLength < 256)
|
||
// {
|
||
// RemoveActivePacket(Packet);
|
||
// }
|
||
|
||
FreePacket(Packet);
|
||
|
||
if (Message->Buffer == LastReceiveBuffer)
|
||
{
|
||
LastReceiveBuffer = 0;
|
||
LastReceiveBufferLength = 0;
|
||
}
|
||
|
||
Message->Buffer = 0;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::CommonReallocBuffer(
|
||
IN RPC_MESSAGE * Message,
|
||
IN unsigned int NewSize
|
||
)
|
||
{
|
||
if (Message->Buffer == LastReceiveBuffer &&
|
||
NewSize <= LastReceiveBufferLength)
|
||
{
|
||
Message->BufferLength = NewSize;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPC_STATUS Status;
|
||
RPC_MESSAGE NewMessage;
|
||
|
||
NewMessage.BufferLength = NewSize;
|
||
|
||
Status = CommonGetBuffer(&NewMessage);
|
||
if (RPC_S_OK != Status)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
LastReceiveBuffer = NewMessage.Buffer;
|
||
LastReceiveBufferLength = NewMessage.BufferLength;
|
||
|
||
if (NewSize >= Message->BufferLength)
|
||
{
|
||
RpcpMemoryCopy(NewMessage.Buffer,
|
||
Message->Buffer,
|
||
Message->BufferLength
|
||
);
|
||
}
|
||
|
||
CommonFreeBuffer(Message);
|
||
|
||
Message->Buffer = NewMessage.Buffer;
|
||
Message->BufferLength = NewMessage.BufferLength;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
void
|
||
DG_PACKET_ENGINE::CleanupSendWindow()
|
||
{
|
||
while (Buffer)
|
||
{
|
||
PopBuffer(FALSE);
|
||
}
|
||
}
|
||
|
||
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()
|
||
/*++
|
||
|
||
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;
|
||
unsigned FragmentsSent = 0;
|
||
|
||
#ifdef DEBUGRPC
|
||
if (!Buffer &&
|
||
(BufferFlags & RPC_BUFFER_PARTIAL))
|
||
{
|
||
// return RPC_S_SEND_INCOMPLETE;
|
||
RpcpBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
if (SendBurstLength > SendWindowSize)
|
||
{
|
||
SendBurstLength = SendWindowSize;
|
||
}
|
||
|
||
//
|
||
// If we can extend the window, do so; otherwise, resend old packets.
|
||
//
|
||
if (FirstUnsentFragment <= FinalSendFrag &&
|
||
FirstUnsentFragment < SendWindowBase + SendWindowSize)
|
||
{
|
||
unsigned short 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) || (BasePacketFlags2 & DG_PF2_UNRELATED)))
|
||
{
|
||
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.
|
||
//
|
||
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 >= 0xdd000000)
|
||
{
|
||
RpcpBreakPoint();
|
||
}
|
||
#endif
|
||
fRetransmitted = TRUE;
|
||
}
|
||
else
|
||
{
|
||
ASSERT(FragNum == FirstUnsentFragment);
|
||
|
||
Offset = FirstUnsentOffset;
|
||
Length = MaxFragmentSize;
|
||
DistanceToEnd = BufferLength - Offset;
|
||
|
||
if (DistanceToEnd < Length)
|
||
{
|
||
Length = DistanceToEnd;
|
||
}
|
||
|
||
FirstUnsentOffset += Length;
|
||
FirstUnsentFragment = 1 + FragNum;
|
||
}
|
||
|
||
if (BufferLength)
|
||
{
|
||
// this is harmless and can sometimes be triggered on the first call of an activity
|
||
// ASSERT(Length);
|
||
// ASSERT(Offset < BufferLength);
|
||
}
|
||
else
|
||
{
|
||
ASSERT(!Length);
|
||
ASSERT(!Offset);
|
||
}
|
||
|
||
//
|
||
// Time to start assembling the buffer.
|
||
//
|
||
pHeader = (PNCA_PACKET_HEADER) (PCHAR(Buffer) - sizeof(NCA_PACKET_HEADER));
|
||
|
||
*pHeader = pSavedPacket->Header;
|
||
|
||
pHeader->PacketType = PacketType;
|
||
pHeader->PacketFlags = BasePacketFlags;
|
||
pHeader->PacketFlags2 = BasePacketFlags2;
|
||
|
||
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->SetPacketBodyLen (Length);
|
||
pHeader->SetFragmentNumber((unsigned short) FragNum);
|
||
|
||
if (FALSE == fFack)
|
||
{
|
||
pHeader->PacketFlags |= DG_PF_NO_FACK;
|
||
}
|
||
|
||
AddSerialNumber(pHeader);
|
||
|
||
RPC_STATUS Status;
|
||
|
||
//
|
||
// Stub data is encrypted in-place; we need not to encrypt the original data
|
||
// so we can retransmit it if necessary.
|
||
//
|
||
unsigned Frag = (pHeader->PacketType << 16) | pHeader->GetFragmentNumber();
|
||
LogEvent(SU_ENGINE, EV_PKT_OUT, this, 0, Frag);
|
||
|
||
if (BaseConnection->ActiveSecurityContext &&
|
||
BaseConnection->ActiveSecurityContext->AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||
{
|
||
RpcpMemoryCopy(&pSavedPacket->Header, pHeader, sizeof(NCA_PACKET_HEADER));
|
||
RpcpMemoryCopy(pSavedPacket->Header.Data, pHeader->Data + Offset, pHeader->GetPacketBodyLen());
|
||
|
||
Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, &pSavedPacket->Header, 0);
|
||
}
|
||
else
|
||
{
|
||
Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, pHeader, Offset);
|
||
}
|
||
|
||
FragmentRingBuffer[Index].SerialNumber = SendSerialNumber;
|
||
FragmentRingBuffer[Index].Length = Length;
|
||
FragmentRingBuffer[Index].Offset = Offset;
|
||
|
||
++SendSerialNumber;
|
||
|
||
if (Status)
|
||
{
|
||
LogError(SU_ENGINE, EV_STATUS, this, 0, Status);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::UpdateSendWindow(
|
||
PDG_PACKET pPacket,
|
||
BOOL * pfUpdated
|
||
)
|
||
/*++
|
||
|
||
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 PDU size or window size changed
|
||
FALSE if not
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = 0;
|
||
|
||
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pPacket->Header.Data;
|
||
|
||
*pfUpdated = FALSE;
|
||
|
||
unsigned short Diff;
|
||
unsigned short RemoteBase = 1+pPacket->GetFragmentNumber();
|
||
|
||
|
||
ASSERT(pPacket->TimeReceived == 0x31415926);
|
||
|
||
//
|
||
// Check that we can understand this packet.
|
||
//
|
||
if (0 != pPacket->GetPacketBodyLen())
|
||
{
|
||
//
|
||
// 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->SetPacketBodyLen(0);
|
||
}
|
||
else if (pPacket->GetPacketBodyLen() < sizeof(FACK_BODY_VER_0))
|
||
{
|
||
#ifdef DEBUGRPC
|
||
PrintToDebugger("RPC DG: warning - FACK body truncated\n");
|
||
#endif
|
||
pPacket->SetPacketBodyLen(0);
|
||
}
|
||
else if (pPacket->GetPacketBodyLen() < sizeof(FACK_BODY_VER_0) + pBody->AckWordCount * sizeof(unsigned long))
|
||
{
|
||
#ifdef DEBUGRPC
|
||
PrintToDebugger("RPC DG: warning - FACK body length inconsistent\n");
|
||
#endif
|
||
pPacket->SetPacketBodyLen(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 the other guy is resending the same FACK, we should resend.
|
||
// If it's different, then we are likely OK.
|
||
//
|
||
if (pBody->SerialNumber == FackSerialNumber)
|
||
{
|
||
goto send;
|
||
}
|
||
|
||
if (pBody->SerialNumber < FackSerialNumber)
|
||
{
|
||
FackSerialNumber = pBody->SerialNumber;
|
||
goto dont_send;
|
||
}
|
||
|
||
FackSerialNumber = pBody->SerialNumber;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Update send window.
|
||
//
|
||
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.
|
||
//
|
||
goto dont_send;
|
||
}
|
||
|
||
if (RemoteBase > FirstUnsentFragment)
|
||
{
|
||
#ifdef DEBUGRPC
|
||
PrintToDebugger("RPC DG: bogus FACK packet received\n");
|
||
#endif
|
||
goto dont_send;
|
||
}
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
Diff = RemoteBase - SendWindowBase;
|
||
|
||
ASSERT(Diff <= MAX_WINDOW_SIZE);
|
||
|
||
#ifdef DEBUGRPC
|
||
while (Diff)
|
||
{
|
||
FragmentRingBuffer[RingBufferBase].SerialNumber |= 0xeeee0000;
|
||
FragmentRingBuffer[RingBufferBase].Length |= 0xdd000000;
|
||
FragmentRingBuffer[RingBufferBase].Offset |= 0xb0000000;
|
||
|
||
++RingBufferBase;
|
||
RingBufferBase %= MAX_WINDOW_SIZE;
|
||
--Diff;
|
||
}
|
||
#else
|
||
RingBufferBase += Diff;
|
||
RingBufferBase %= MAX_WINDOW_SIZE;
|
||
#endif
|
||
|
||
SendWindowBase = RemoteBase;
|
||
SendWindowBits = 0;
|
||
|
||
ASSERT( SendWindowBase <= FirstUnsentFragment );
|
||
|
||
if (IsBufferAcknowledged())
|
||
{
|
||
PopBuffer(FALSE);
|
||
}
|
||
|
||
if (0 != pPacket->GetPacketBodyLen())
|
||
{
|
||
LogEvent(SU_ENGINE, EV_WINDOW, this, (void *) pBody->WindowSize, pBody->Acks[0]);
|
||
|
||
if (pBody->AckWordCount)
|
||
{
|
||
//
|
||
// 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 > SourceEndpoint->Stats.PreferredPduSize)
|
||
{
|
||
NewPduSize = SourceEndpoint->Stats.PreferredPduSize;
|
||
}
|
||
|
||
BaseConnection->CurrentPduSize = (unsigned short) NewPduSize;
|
||
BaseConnection->RemoteWindowSize = pBody->WindowSize;
|
||
|
||
//
|
||
// If no packets are getting through, we probably are sending
|
||
// packets that are too large.
|
||
//
|
||
if (0 == RemoteBase &&
|
||
0 == SendWindowBits &&
|
||
NewPduSize < CurrentPduSize)
|
||
{
|
||
CurrentPduSize = (unsigned short) NewPduSize;
|
||
SetFragmentLengths();
|
||
|
||
FirstUnsentFragment = 0;
|
||
FirstUnsentOffset = 0;
|
||
FinalSendFrag = SendWindowBase + (BufferLength-1) / MaxFragmentSize;
|
||
}
|
||
|
||
*pfUpdated = TRUE;
|
||
}
|
||
|
||
send:
|
||
|
||
Status = SendSomeFragments();
|
||
|
||
dont_send:
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
BOOL
|
||
DG_PACKET_ENGINE::UpdateReceiveWindow(
|
||
PDG_PACKET pPacket
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds a fragment to the receive list, and sends a FACK.
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
ASSERT(pPacket->TimeReceived == 0x31415926);
|
||
|
||
//
|
||
// Don't retain data from previous pipe buffers.
|
||
//
|
||
if (pPacket->GetFragmentNumber() < ReceiveFragmentBase)
|
||
{
|
||
if (0 == (pPacket->Header.PacketFlags & DG_PF_NO_FACK))
|
||
{
|
||
SendFackOrNocall(pPacket, DG_FACK);
|
||
}
|
||
|
||
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) > BaseConnection->CurrentPduSize)
|
||
{
|
||
unsigned RemoteTransportBuffer = BaseConnection->CurrentPduSize * BaseConnection->RemoteWindowSize;
|
||
|
||
BaseConnection->CurrentPduSize = ((pPacket->DataLength + sizeof(NCA_PACKET_HEADER)) & ~7);
|
||
BaseConnection->RemoteWindowSize = RemoteTransportBuffer / BaseConnection->CurrentPduSize;
|
||
if (0 == BaseConnection->RemoteWindowSize)
|
||
{
|
||
BaseConnection->RemoteWindowSize = 1;
|
||
}
|
||
}
|
||
|
||
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_PF2_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 );
|
||
return FALSE;
|
||
}
|
||
|
||
pReceivedPackets = pPacket;
|
||
pLastConsecutivePacket = pPacket;
|
||
|
||
pPacket->pNext = pPacket->pPrevious = 0;
|
||
|
||
ConsecutiveDataBytes += pHeader->GetPacketBodyLen();
|
||
|
||
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->GetFragmentNumber())
|
||
{
|
||
pLastConsecutivePacket = pPacket;
|
||
ConsecutiveDataBytes += pHeader->GetPacketBodyLen();
|
||
}
|
||
|
||
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->GetFragmentNumber();
|
||
|
||
if (pLastConsecutivePacket)
|
||
{
|
||
pScan = pLastConsecutivePacket;
|
||
}
|
||
else
|
||
{
|
||
pScan = pReceivedPackets;
|
||
}
|
||
|
||
pTrail = 0;
|
||
while (pScan && pScan->GetFragmentNumber() < FragNum)
|
||
{
|
||
ASSERT(pScan->TimeReceived == 0x31415926);
|
||
ASSERT(pScan->Header.SequenceNumber == SequenceNumber);
|
||
|
||
pTrail = pScan;
|
||
pScan = pScan->pNext;
|
||
}
|
||
|
||
if (pScan != 0)
|
||
{
|
||
if (pScan->GetFragmentNumber() > FragNum)
|
||
{
|
||
if (pScan->pPrevious &&
|
||
pScan->pPrevious->GetFragmentNumber() >= 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->GetFragmentNumber() + 1;
|
||
}
|
||
else
|
||
{
|
||
pScan = pReceivedPackets;
|
||
ScanNum = ReceiveFragmentBase;
|
||
}
|
||
|
||
while (pScan)
|
||
{
|
||
if (ScanNum == pScan->GetFragmentNumber())
|
||
{
|
||
ConsecutiveDataBytes += pScan->GetPacketBodyLen();
|
||
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))
|
||
{
|
||
SendFackOrNocall(pPacket, DG_FACK);
|
||
}
|
||
|
||
return PacketAddedToList;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::SendFackOrNocall(
|
||
PDG_PACKET pPacket,
|
||
unsigned char PacketType
|
||
)
|
||
{
|
||
unsigned ReceiveWindowSize;
|
||
|
||
ReceiveWindowSize = SourceEndpoint->Stats.ReceiveBufferSize
|
||
/ ((1+SourceEndpoint->NumberOfCalls) * CurrentPduSize);
|
||
|
||
if (0 == ReceiveWindowSize)
|
||
{
|
||
ReceiveWindowSize = 1;
|
||
}
|
||
else if (ReceiveWindowSize > MAX_WINDOW_SIZE)
|
||
{
|
||
ReceiveWindowSize = MAX_WINDOW_SIZE;
|
||
}
|
||
|
||
pSavedPacket->Header.PacketType = PacketType;
|
||
pSavedPacket->Header.SequenceNumber = SequenceNumber;
|
||
pSavedPacket->Header.PacketFlags2 = 0;
|
||
|
||
FACK_BODY_VER_0 PAPI * pBody = (FACK_BODY_VER_0 PAPI *) pSavedPacket->Header.Data;
|
||
|
||
pBody->Version = 1;
|
||
pBody->Pad1 = 0;
|
||
pBody->MaxDatagramSize = SourceEndpoint->Stats.PreferredPduSize;
|
||
pBody->MaxPacketSize = SourceEndpoint->Stats.MaxPacketSize;
|
||
pBody->AckWordCount = 1;
|
||
pBody->WindowSize = (unsigned short) ReceiveWindowSize;
|
||
|
||
if (pPacket)
|
||
{
|
||
pBody->SerialNumber = ReadSerialNumber(&pPacket->Header);
|
||
}
|
||
else
|
||
{
|
||
pBody->SerialNumber = ReceiveSerialNumber;
|
||
}
|
||
|
||
unsigned short FragNum = ReceiveFragmentBase-1;
|
||
PDG_PACKET pScan = 0;
|
||
|
||
if (pLastConsecutivePacket)
|
||
{
|
||
FragNum = pLastConsecutivePacket->GetFragmentNumber();
|
||
pScan = pLastConsecutivePacket->pNext;
|
||
}
|
||
else if (pReceivedPackets)
|
||
{
|
||
pScan = pReceivedPackets->pNext;
|
||
}
|
||
|
||
unsigned Bit;
|
||
pBody->Acks[0] = 0;
|
||
|
||
while ( pScan )
|
||
{
|
||
Bit = pScan->GetFragmentNumber() - FragNum - 1;
|
||
|
||
pBody->Acks[0] |= (1 << Bit);
|
||
|
||
pScan = pScan->pNext;
|
||
}
|
||
|
||
if (pBody->Acks[0] == 0)
|
||
{
|
||
pBody->AckWordCount = 0;
|
||
}
|
||
|
||
pSavedPacket->SetPacketBodyLen( sizeof(FACK_BODY_VER_0) + sizeof(unsigned long) );
|
||
pSavedPacket->SetFragmentNumber(FragNum);
|
||
|
||
AddSerialNumber(&pSavedPacket->Header);
|
||
|
||
unsigned Frag = (pSavedPacket->Header.PacketType << 16) | pSavedPacket->GetFragmentNumber();
|
||
LogEvent(SU_ENGINE, EV_PKT_OUT, this, 0, Frag);
|
||
|
||
RPC_STATUS Status;
|
||
|
||
Status = BaseConnection->SealAndSendPacket(SourceEndpoint, RemoteAddress, &pSavedPacket->Header, 0);
|
||
|
||
if (Status)
|
||
{
|
||
LogError(SU_ENGINE, EV_STATUS, this, 0, Status);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DG_PACKET_ENGINE::AssembleBufferFromPackets(
|
||
RPC_MESSAGE * Message,
|
||
CALL * Call
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function coalesces the list of consecutive packets into a monolithic
|
||
buffer.
|
||
|
||
Arguments:
|
||
|
||
Message - if .Buffer != 0 , use it. Otherwise allocate one.
|
||
|
||
Call - 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->GetPacketBodyLen());
|
||
|
||
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 = Call->GetBuffer(Message, 0);
|
||
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::FromStubData(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->GetFragmentNumber());
|
||
|
||
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->GetPacketBodyLen();
|
||
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;
|
||
}
|
||
|
||
|
||
void
|
||
DG_PACKET_ENGINE::SetFragmentLengths()
|
||
{
|
||
PSECURITY_CONTEXT pSecurityContext = BaseConnection->ActiveSecurityContext;
|
||
|
||
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 = (unsigned short) pSecurityContext->MaximumSignatureLength();
|
||
SecurityTrailerSize += (unsigned short) Align4(sizeof(DG_SECURITY_TRAILER));
|
||
break;
|
||
}
|
||
|
||
case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
|
||
{
|
||
SecurityTrailerSize = (unsigned short) pSecurityContext->MaximumHeaderLength();
|
||
SecurityTrailerSize += (unsigned short) Align(sizeof(DG_SECURITY_TRAILER), Align4(pSecurityContext->BlockSize()));
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
ASSERT(0 && "RPC: unknown protect level");
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (CurrentPduSize != BaseConnection->CurrentPduSize)
|
||
{
|
||
CurrentPduSize = (unsigned short) BaseConnection->CurrentPduSize;
|
||
SendWindowSize = (unsigned short) BaseConnection->RemoteWindowSize;
|
||
}
|
||
|
||
MaxFragmentSize = CurrentPduSize - sizeof(NCA_PACKET_HEADER);
|
||
|
||
if (SecurityTrailerSize)
|
||
{
|
||
MaxFragmentSize -= SecurityTrailerSize;
|
||
MaxFragmentSize -= MaxFragmentSize % SECURITY_HEADER_ALIGNMENT;
|
||
}
|
||
}
|
||
|
||
|
||
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));
|
||
pPacket->Header.ServerBootTime = RpcpByteSwapLong(pPacket->Header.ServerBootTime);
|
||
*VerNum = RpcpByteSwapLong(*VerNum);
|
||
pPacket->Header.SequenceNumber = RpcpByteSwapLong(pPacket->Header.SequenceNumber);
|
||
pPacket->Header.OperationNumber = RpcpByteSwapShort(pPacket->Header.OperationNumber);
|
||
pPacket->Header.InterfaceHint = RpcpByteSwapShort(pPacket->Header.InterfaceHint);
|
||
pPacket->Header.ActivityHint = RpcpByteSwapShort(pPacket->Header.ActivityHint);
|
||
pPacket->Header.PacketBodyLen = RpcpByteSwapShort(pPacket->Header.PacketBodyLen);
|
||
pPacket->Header.FragmentNumber = RpcpByteSwapShort(pPacket->Header.FragmentNumber);
|
||
}
|
||
|
||
|
||
void
|
||
ByteSwapFackBody0(
|
||
FACK_BODY_VER_0 __RPC_FAR * pBody
|
||
)
|
||
{
|
||
pBody->WindowSize = RpcpByteSwapShort(pBody->WindowSize);
|
||
pBody->MaxDatagramSize = RpcpByteSwapLong (pBody->MaxDatagramSize);
|
||
pBody->MaxPacketSize = RpcpByteSwapLong (pBody->MaxPacketSize);
|
||
pBody->SerialNumber = RpcpByteSwapShort(pBody->SerialNumber);
|
||
pBody->AckWordCount = RpcpByteSwapShort(pBody->AckWordCount);
|
||
|
||
unsigned u;
|
||
for (u=0; u < pBody->AckWordCount; ++u)
|
||
{
|
||
pBody->Acks[u] = RpcpByteSwapLong (pBody->Acks[u]);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
RPCRTAPI RPC_STATUS RPC_ENTRY
|
||
I_RpcTransDatagramAllocate(
|
||
IN DG_TRANSPORT_ENDPOINT TransportEndpoint,
|
||
OUT BUFFER *pBuffer,
|
||
OUT PUINT pBufferLength,
|
||
OUT DatagramTransportPair **pAddressPair
|
||
)
|
||
{
|
||
DG_ENDPOINT * Endpoint = DG_ENDPOINT::FromEndpoint(TransportEndpoint);
|
||
RPC_DATAGRAM_TRANSPORT * Transport = Endpoint->TransportInterface;
|
||
|
||
if ( !Endpoint->Stats.PreferredPduSize )
|
||
{
|
||
RpcpBreakPoint();
|
||
}
|
||
|
||
DG_PACKET * Packet = DG_PACKET::AllocatePacket(Endpoint->Stats.PreferredPduSize
|
||
+ Transport->AddressSize
|
||
+ sizeof(DatagramTransportPair));
|
||
if (!Packet)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
DG_TRANSPORT_ADDRESS Address = DG_TRANSPORT_ADDRESS(Packet->Header.Data - sizeof(NCA_PACKET_HEADER) + Endpoint->Stats.PreferredPduSize);
|
||
|
||
*pBuffer = &Packet->Header;
|
||
*pBufferLength = Endpoint->Stats.PreferredPduSize;
|
||
*pAddressPair = (DatagramTransportPair *)((char *)Address + Transport->AddressSize);
|
||
(*pAddressPair)->RemoteAddress = Address;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPCRTAPI RPC_STATUS RPC_ENTRY
|
||
I_RpcTransDatagramAllocate2(
|
||
IN DG_TRANSPORT_ENDPOINT TransportEndpoint,
|
||
OUT BUFFER *pBuffer,
|
||
IN OUT PUINT pBufferLength,
|
||
OUT DG_TRANSPORT_ADDRESS *pAddress
|
||
)
|
||
{
|
||
DG_ENDPOINT *pEndpoint = DG_ENDPOINT::FromEndpoint(TransportEndpoint);
|
||
RPC_DATAGRAM_TRANSPORT *pTransport = pEndpoint->TransportInterface;
|
||
DWORD dwSize = *pBufferLength;
|
||
|
||
if (dwSize < pEndpoint->Stats.PreferredPduSize)
|
||
{
|
||
dwSize = pEndpoint->Stats.PreferredPduSize;
|
||
}
|
||
|
||
DG_PACKET * Packet = DG_PACKET::AllocatePacket( dwSize + pTransport->AddressSize);
|
||
|
||
if (!Packet)
|
||
{
|
||
return RPC_S_OUT_OF_MEMORY;
|
||
}
|
||
|
||
DG_TRANSPORT_ADDRESS Address = DG_TRANSPORT_ADDRESS(Packet->Header.Data - sizeof(NCA_PACKET_HEADER) + dwSize);
|
||
|
||
*pBuffer = &Packet->Header;
|
||
*pBufferLength = dwSize;
|
||
*pAddress = Address;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPCRTAPI RPC_STATUS RPC_ENTRY
|
||
I_RpcTransDatagramFree(
|
||
IN RPC_TRANSPORT_ADDRESS ThisAddress,
|
||
IN BUFFER Buffer
|
||
)
|
||
{
|
||
DG_PACKET * Packet = DG_PACKET::FromPacketHeader( Buffer );
|
||
|
||
Packet->Free();
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
RPC_STATUS
|
||
DG_PACKET::Initialize(
|
||
)
|
||
{
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
BOOL
|
||
DG_PACKET::DeleteIdlePackets(
|
||
long CurrentTime
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This fn scans the free packet list for very old packets and deletes them.
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
DG_COMMON_CONNECTION::DG_COMMON_CONNECTION(
|
||
RPC_DATAGRAM_TRANSPORT *a_TransportInterface,
|
||
RPC_STATUS * pStatus
|
||
) :
|
||
Mutex (pStatus),
|
||
TimeStamp (0),
|
||
TransportInterface (a_TransportInterface),
|
||
ReferenceCount (0),
|
||
CurrentPduSize (a_TransportInterface->BasePduSize),
|
||
RemoteWindowSize (1),
|
||
RemoteDataUpdated (FALSE),
|
||
LowestActiveSequence(0),
|
||
LowestUnusedSequence(0),
|
||
ActiveSecurityContext(0)
|
||
{
|
||
}
|
||
|
||
DG_COMMON_CONNECTION::~DG_COMMON_CONNECTION()
|
||
{
|
||
delete ActiveSecurityContext;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
SendSecurePacket(
|
||
IN DG_ENDPOINT * SourceEndpoint,
|
||
IN DG_TRANSPORT_ADDRESS RemoteAddress,
|
||
IN UNALIGNED NCA_PACKET_HEADER *pHeader,
|
||
IN unsigned long DataOffset,
|
||
IN SECURITY_CONTEXT * SecurityContext
|
||
)
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
unsigned TrailerLength = 0;
|
||
unsigned MaxTrailerSize = 0;
|
||
|
||
PDG_SECURITY_TRAILER pTrailer = 0;
|
||
|
||
if (SecurityContext && SecurityContext->AuthenticationLevel > RPC_C_AUTHN_LEVEL_NONE)
|
||
{
|
||
// Pad the stub data length to a multiple of 8, so the security
|
||
// trailer is properly aligned. OSF requires that the pad bytes
|
||
// be included in PacketBodyLen.
|
||
//
|
||
pHeader->SetPacketBodyLen(Align8(pHeader->GetPacketBodyLen()));
|
||
|
||
pHeader->AuthProto = (unsigned char) SecurityContext->AuthenticationService;
|
||
|
||
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 = pHeader;
|
||
SecurityBuffers[0].cbBuffer = sizeof(NCA_PACKET_HEADER);
|
||
|
||
SecurityBuffers[1].BufferType = SECBUFFER_DATA;
|
||
SecurityBuffers[1].pvBuffer = pHeader->Data + DataOffset;
|
||
SecurityBuffers[1].cbBuffer = pHeader->GetPacketBodyLen();
|
||
|
||
if (SecurityContext->AuthenticationLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||
{
|
||
SecurityBuffers[2].cbBuffer = (ULONG) Align(sizeof(DG_SECURITY_TRAILER), Align4(SecurityContext->BlockSize()));
|
||
SecurityBuffers[3].cbBuffer = SecurityContext->MaximumHeaderLength();
|
||
}
|
||
else
|
||
{
|
||
SecurityBuffers[2].cbBuffer = (ULONG) Align4(sizeof(DG_SECURITY_TRAILER));
|
||
SecurityBuffers[3].cbBuffer = SecurityContext->MaximumSignatureLength();
|
||
}
|
||
|
||
pTrailer = (PDG_SECURITY_TRAILER) _alloca(SecurityBuffers[2].cbBuffer + SecurityBuffers[3].cbBuffer);
|
||
|
||
SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
|
||
SecurityBuffers[2].pvBuffer = pTrailer;
|
||
|
||
SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
|
||
SecurityBuffers[3].pvBuffer = (unsigned char *) pTrailer
|
||
+ 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 = pHeader->GetFragmentNumber();
|
||
MsgSecurityInfo.ReceiveSequenceNumber = SecurityContext->AuthContextId;
|
||
MsgSecurityInfo.PacketType = ~0;
|
||
|
||
TrailerLength = SecurityBuffers[2].cbBuffer;
|
||
|
||
pTrailer->protection_level = (unsigned char) SecurityContext->AuthenticationLevel;
|
||
pTrailer->key_vers_num = (unsigned char) SecurityContext->AuthContextId;
|
||
|
||
Status = SecurityContext->SignOrSeal (
|
||
pHeader->SequenceNumber,
|
||
SecurityContext->AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
&BufferDescriptor );
|
||
|
||
ASSERT( SecurityBuffers[3].cbBuffer > 0 );
|
||
|
||
TrailerLength += SecurityBuffers[3].cbBuffer;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Unsecure packet.
|
||
//
|
||
pHeader->AuthProto = 0;
|
||
}
|
||
|
||
if (RPC_S_OK == Status)
|
||
{
|
||
Status = SourceEndpoint->TransportInterface->Send(
|
||
&SourceEndpoint->TransportEndpoint,
|
||
RemoteAddress,
|
||
pHeader,
|
||
sizeof(NCA_PACKET_HEADER),
|
||
pHeader->Data + DataOffset,
|
||
pHeader->GetPacketBodyLen(),
|
||
pTrailer,
|
||
TrailerLength
|
||
);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
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->GetPacketBodyLen());
|
||
|
||
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->GetPacketBodyLen();
|
||
|
||
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 = (ULONG) Align(sizeof(DG_SECURITY_TRAILER), Alignment);
|
||
SecurityBuffers[3].pvBuffer = AlignPtr(pVerifier + 1, Alignment);
|
||
}
|
||
else
|
||
{
|
||
SecurityBuffers[2].cbBuffer = (ULONG) Align4(sizeof(DG_SECURITY_TRAILER));
|
||
SecurityBuffers[3].pvBuffer = AlignPtr4(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->GetFragmentNumber();
|
||
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)
|
||
{
|
||
#ifdef DEBUGRPC
|
||
DbgPrint("dg rpc: %lx: pkt %lx type %lx has bad security info (error 0x%lx)\n",
|
||
GetCurrentProcessId(), pPacket, pPacket->Header.PacketType, Status);
|
||
#endif
|
||
|
||
ASSERT(Status == RPC_S_ACCESS_DENIED ||
|
||
Status == ERROR_SHUTDOWN_IN_PROGRESS ||
|
||
Status == ERROR_PASSWORD_MUST_CHANGE ||
|
||
Status == ERROR_PASSWORD_EXPIRED ||
|
||
Status == ERROR_ACCOUNT_DISABLED ||
|
||
Status == ERROR_INVALID_LOGON_HOURS);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
BOOL
|
||
DG_PickleEEInfoIntoPacket (
|
||
IN DG_PACKET * Packet,
|
||
IN size_t PickleStartOffset
|
||
)
|
||
/*++
|
||
Function Name: PickeEEInfoIntoPacket
|
||
|
||
Parameters:
|
||
PickleStartOffset - the offset in bytes where the pickling starts
|
||
pHeader - pointer to the packet to fill
|
||
|
||
Description:
|
||
Checks for EEInfo on the thread, trims the EEInfo to Packet->MaxDataLength,
|
||
and pickles the EEInfo starting from PickleStartOffset.
|
||
|
||
Returns:
|
||
TRUE if EEInfo was pickled. FALSE if not.
|
||
|
||
--*/
|
||
{
|
||
BOOL fEEInfoPresent = FALSE;
|
||
ExtendedErrorInfo *EEInfo;
|
||
RPC_STATUS RpcStatus;
|
||
size_t CurrentPacketSize;
|
||
|
||
EEInfo = RpcpGetEEInfo();
|
||
if (EEInfo)
|
||
{
|
||
AddComputerNameToChain(EEInfo);
|
||
TrimEEInfoToLength (Packet->MaxDataLength, &CurrentPacketSize);
|
||
if (CurrentPacketSize != 0)
|
||
{
|
||
CurrentPacketSize += PickleStartOffset;
|
||
|
||
ASSERT(IsBufferAligned(Packet->Header.Data + PickleStartOffset));
|
||
|
||
RpcpMemorySet(Packet->Header.Data, 0, CurrentPacketSize);
|
||
|
||
RpcStatus = PickleEEInfo( EEInfo,
|
||
Packet->Header.Data + PickleStartOffset,
|
||
CurrentPacketSize - PickleStartOffset
|
||
);
|
||
|
||
if (RpcStatus == RPC_S_OK)
|
||
{
|
||
fEEInfoPresent = TRUE;
|
||
Packet->SetPacketBodyLen( CurrentPacketSize );
|
||
}
|
||
}
|
||
}
|
||
|
||
return fEEInfoPresent;
|
||
}
|
||
|
||
|
||
void
|
||
InitErrorPacket(
|
||
DG_PACKET * pPacket,
|
||
unsigned char PacketType,
|
||
RPC_STATUS RpcStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Maps <ProcessStatus> to an NCA error code and sends
|
||
a FAULT or REJECT packet to the client, as appropriate.
|
||
|
||
Arguments:
|
||
|
||
pSendPacket - a packet to use, or zero if this fn should allocate one
|
||
|
||
ProcessStatus - NT RPC error code
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
NCA_PACKET_HEADER * pHeader = &pPacket->Header;
|
||
|
||
CleanupPacket(pHeader);
|
||
|
||
pHeader->PacketType = PacketType;
|
||
|
||
size_t FaultSize;
|
||
BOOL fEEInfoPresent = FALSE;
|
||
|
||
//
|
||
// This mapping distinguishes client-side shutdown from server-side shutdown.
|
||
//
|
||
if (RpcStatus == ERROR_SHUTDOWN_IN_PROGRESS)
|
||
{
|
||
if (PacketType == DG_REJECT)
|
||
{
|
||
RpcStatus = RPC_S_SERVER_UNAVAILABLE;
|
||
}
|
||
else
|
||
{
|
||
RpcStatus = ERROR_SERVER_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
}
|
||
else if (RpcStatus == RPC_P_CLIENT_SHUTDOWN_IN_PROGRESS)
|
||
{
|
||
RpcStatus = ERROR_SHUTDOWN_IN_PROGRESS;
|
||
}
|
||
|
||
if (g_fSendEEInfo)
|
||
{
|
||
fEEInfoPresent = DG_PickleEEInfoIntoPacket( pPacket, FIELD_OFFSET( EXTENDED_FAULT_BODY, EeInfo) );
|
||
}
|
||
|
||
if (fEEInfoPresent)
|
||
{
|
||
//
|
||
// Packet body length already set.
|
||
//
|
||
EXTENDED_FAULT_BODY * body = (EXTENDED_FAULT_BODY *) pHeader->Data;
|
||
|
||
body->NcaStatus = MapToNcaStatusCode(RpcStatus);
|
||
body->Magic = DG_EE_MAGIC_VALUE;
|
||
body->reserved1 = 0;
|
||
body->reserved2 = 0;
|
||
}
|
||
else
|
||
{
|
||
size_t XopenFaultSize = sizeof(unsigned long);
|
||
|
||
*(unsigned long *)(pHeader->Data) = MapToNcaStatusCode(RpcStatus);
|
||
|
||
pHeader->SetPacketBodyLen(XopenFaultSize);
|
||
}
|
||
}
|
||
|
||
|