ClientEventChainedReceive routine

The ClientEventChainedReceive routine 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.

The transport calls this handler, rather than ClientEventReceive, when it is forwarding a full TSDU indicated to the transport by an NDIS miniport driver and the client can be given direct read-only access to the buffered TSDU until the client has consumed the data.

Syntax

NTSTATUS ClientEventChainedReceive(
  _In_ PVOID              TdiEventContext,
  _In_ CONNECTION_CONTEXT ConnectionContext,
  _In_ ULONG              ReceiveFlags,
  _In_ ULONG              ReceiveLength,
  _In_ ULONG              StartingOffset,
  _In_ PMDL               Tsdu,
  _In_ PVOID              TsduDescriptor
);

Parameters

  • TdiEventContext [in]
    Pointer to the client-supplied context provided in the IRP that was set up with TdiBuildSetEventHandler when ClientEventChainedReceive was registered with the underlying transport.

  • ConnectionContext [in]
    Pointer to the client's context area for this connection endpoint. The client previously supplied this value to its underlying transport when its ClientEventConnect handler accepted a connection offer from the remote-node peer and/or when it opened the connection endpoint with ZwCreateFile.

  • ReceiveFlags [in]
    Specifies the nature of the receive indication as a combination (ORed) of the following flags:

    • TDI_RECEIVE_NORMAL
      The buffer mapped at Tsdu contains normal data received from the client's remote-node peer. This flag and TDI_RECEIVE_EXPEDITED are mutually exclusive.

    • TDI_RECEIVE_EXPEDITED
      The buffer mapped at Tsdu contains expedited data received from the client's remote-node peer. This flag can be set only if the client did not register either or both ClientEventChainedReceiveExpedited and/or ClientEventReceiveExpedited handler(s) and if the underlying transports support expedited transfers.

    • TDI_RECEIVE_ENTIRE_MESSAGE
      The buffer mapped at Tsdu contains a full TSDU, and the client retains read-only access to this buffer until the client consumes the indicated data if ClientEventChainedReceive returns STATUS_PENDING. This flag is always set when ClientEventChainedReceive is called.

  • ReceiveLength [in]
    Specifies the number of bytes of client data in the buffer mapped at Tsdu.

  • StartingOffset [in]
    Specifies the byte offset at which the client data starts within the buffer mapped at Tsdu.

  • Tsdu [in]
    Pointer to an MDL, possibly the initial MDL in a chain, mapping the buffer containing the received TSDU.

  • TsduDescriptor [in]
    Pointer to a descriptor for the received TSDU. The client must call TdiReturnChainedReceives with this pointer subsequently if it returns STATUS_PENDING for this receive indication. This pointer should be treated as a handle to an opaque variable, to be used by the client only as a parameter to TdiReturnChainedReceives if ClientEventChainedReceive returns STATUS_PENDING.

Return value

ClientEventChainedReceive can return one of the following:

Return code Description
STATUS_SUCCESS

Indicates the client consumed all the data in the given TSDU and is returning ownership of the buffer (and TsduDescriptor) immediately.

STATUS_PENDING

Indicates the client is retaining ownership of the buffer containing the given TSDU until it calls TdiReturnChainedReceives with the given TsduDescriptor.

STATUS_DATA_NOT_ACCEPTED

Indicates the client is not interested in the TSDU.

If the underlying transport buffers receives internally, the client might retrieve the data with a TDI_RECEIVE request, unless the transport discards buffered data indicated to ClientEventChainedReceive(Xxx) handlers.

 

Remarks

A call to ClientEventChainedReceive gives the client read-only access to the indicated TSDU for the range within the buffer specified by the input StartingOffset and ReceiveLength. If the indicated data is of interest to the client, ClientEventChainedReceive either copies the indicated range of TSDU data into a client-allocated internal buffer and returns STATUS_SUCCESS immediately or retains control of the buffer by returning STATUS_PENDING. If it returns STATUS_PENDING, the client must call TdiReturnChainedReceives subsequently with the input TsduDescriptor to relinquish control of the buffer after the client has consumed the data.

In general, such a call to TdiReturnChainedReceives should occur as quickly as possible. Holding on to a buffer passed to ClientEventChainedReceive for any extended period constrains I/O throughput in underlying driver(s), because the NDIS miniport driver that allocated the buffer cannot reuse this resource for subsequent receive indications until TdiReturnChainedReceives is called.

Because calls to ClientEventChainedReceive always indicate the availability of a full TSDU, the client never has to set up TDI_RECEIVE requests for such an indication, as the corresponding ClientEventReceive handler sometimes must to obtain a full TSDU. Consequently, receive indications made to ClientEventChainedReceive increase network I/O throughput and performance by decreasing call overhead for the client, for its underlying transport, and for the system overall.

If the client has registered only ClientEventChainedReceive and ClientEventReceive handlers for the endpoint-to-endpoint connection, ClientEventChainedReceive can determine whether the TSDU is normal or expedited data by checking the ReceiveFlags, assuming both transports support expedited sends and receives. A transport never calls the corresponding ClientEventReceive handler with the same indication it makes to ClientEventChainedReceive.

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)Receive(Expedited) in the process of indicating a normal TSDU if an expedited TSDU comes in from the remote-node peer.

When ClientEventChainedReceive returns control with either STATUS_SUCCESS or STATUS_DATA_NOT_ACCEPTED, the underlying transport assumes the client is done with this receive indication. If the client returns STATUS_PENDING, the transport assumes it has no way of tracking completion of this receive indication because the client is responsible for calling TdiReturnChainedReceives when it has consumed the indicated TSDU.

ClientEventChainedReceive must be capable of carrying out its operations at IRQL = DISPATCH_LEVEL.

Note   The TDI feature is deprecated and will be removed in future versions of Microsoft Windows. Depending on how you use TDI, use either the Winsock Kernel (WSK) or Windows Filtering Platform (WFP). For more information about WFP and WSK, see Windows Filtering Platform and Winsock Kernel. For a Windows Core Networking blog entry about WSK and TDI, see Introduction to Winsock Kernel (WSK).

 

Requirements

Target platform

Desktop

Header

Tdikrnl.h (include TdiKrnl.h)

IRQL

DISPATCH_LEVEL (see Remarks section)

See also

ClientEventChainedReceiveExpedited

ClientEventReceive

TdiBuildReceive

TdiBuildSetEventHandler

TdiReturnChainedReceives

 

 

Send comments about this topic to Microsoft