NTSTATUS
ClientEventReceive (
IN PVOID TdiEventContext,
IN CONNECTION_CONTEXT ConnectionContext,
IN ULONG ReceiveFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
);
ClientEventReceive is an event handler that the underlying TDI transport calls in response to an incoming receive from a remote node with which the client has an established endpoint-to-endpoint connection. Usually, this is a normal TSDU unless the client has not registered a ClientEventReceiveExpedited handler.
If this flag is clear, ClientEventReceive must check the BytesIndicated
and BytesAvailable parameters to determine how much of the TSDU has
been provided. Although legacy TDI transports continue to set the
TDI_RECEIVE_PARTIAL flag, newer transports leave clear the
TDI_RECEIVE_ENTIRE_MESSAGE flag to indicate partial TSDUs to their clients.
ClientEventReceive can return one of the following:
ClientEventReceive accepts or rejects a TSDU that its underlying TDI driver has received on an established endpoint-to-endpoint connection. The TSDU consists of stream-mode or message-mode data that represents a segment of a data stream, an entire message, or a piece of a message. The transport has removed the transport-layer header from the TSDU before it calls ClientEventReceive.
ClientEventReceive copies normal data the TDI driver receives over the network. The transport does not call ClientEvent(Chained)Receive while the client has an outstanding normal receive request or has rejected previously indicated data for a particular incoming normal receive until that receive is done. However, a transport that supports expedited data can call ClientEvent(Chained)ReceiveExpedited in the process of indicating a normal TSDU if an expedited TSDU comes in from the remote-node peer.
A message-mode transport delimits messages using end-of-record marks. Such a transport can make a sequence of separate receive indications for each block of data terminated with an end-of-record mark within a particular received TSDU. Such a receive usually indicates that the remote-node client issued a sequence of sends to transmit the TSDU.
When ClientEventReceive is called, it can do one of the following:
STATUS_MORE_PROCESSING_REQUIRED if the client is supplying a TDI_RECEIVE request at IoRequestPacket to obtain the remaining TSDU data
STATUS_SUCCESS if the transport is expected to call ClientEventReceive again with the remaining TSDU data
When it has finished copying receive data, ClientEventReceive sets the variable at BytesTaken to the number of bytes of data accepted before it returns control.
If ClientEventReceive supplies a TDI_RECEIVE request at IoRequestPacket for the underlying driver, the transport retrieves the data that it has not yet delivered to the client, along with any new data that is available. Retrieval continues until the client-supplied buffer in the IRP is full or the transport encounters an end-of-record mark. The transport always completes the given IRP before it issues a subsequent call to ClientEvent(Chained)Receive handler for this client. In effect, a client processes each normal TSDU received to completion before the transport will indicate a subsequent normal receive to the client. This allows each client to synchronize receive data correctly.
If ClientEventReceive returns STATUS_DATA_NOT_ACCEPTED after the client has accepted some data from a TSDU, the TDI driver proceeds according to the amount of indicated data the client has accepted and the availability of additional data, as follows:
In these circumstances, a transport can optionally initiate protocol-flow-control action to prevent retransmissions of data from the remote-node transport until the local-node client makes the receive request.
A TDI transport is not required to correlate data reception from the network with TDI_EVENT_RECEIVE indications. If the driver provides internal buffering, it can acknowledge data at any time and make receive indications as necessary, for instance, when it has received a certain amount of data or when its internal buffers are nearly full. A buffering driver should retain any data that its client does not accept in an indication until that client notifies the transport that the client's receive request is satisfied. A transport that does not support internal data buffering can acknowledge received data after its client has accepted the data from ClientEventReceive or after the driver has transferred the received data into a client-supplied IRP.
A received TSDU can be any length up to a transport-specific limit, which the client can find by submitting a request set up with TdiBuildQueryInformation for the QType TDI_QUERY_CONNECTION_INFO and examining the value returned for ReceiveBufferSize if the transport buffers received data internally. However, ClientEventReceive does not necessarily receive an entire TSDU, or even the available portion of a TSDU, each time this handler is called. Each TDI transport can set its own limits on the minimum and maximum amounts of data it will indicate at each receive to its clients, as long as its minimum is at least 128 bytes. The client can find these limits by submitting another query-information request for the QType TDI_QUERY_PROVIDER_INFO and examining the values returned for MinimumLookaheadData and MaximumLookaheadData.
By default, ClientEventReceive runs at IRQL DISPATCH_LEVEL.
ClientEventChainedReceive, ClientEventReceiveExpedited, ClientEventReceiveDatagram, TdiBuildInternalDeviceControlIrp, TdiBuildQueryInformation, TdiBuildReceive, TdiBuildSetEventHandler