xp tdi supprots ClientEventSendPossible ?

Anyone has ever tried ClientEventSendPossible ?
It always returns STATUS_INVALID_PARAMETER :frowning:

It’s caused by “buffer sends” ? Anyone knows how to enable this feature ?
I could not get any information about it from ddk documents.

The same to the callback of TDI_EVENT_CHAINED_RECEIVE_EXPEDITE.

I tried to set the two EventHandlers both before and after the connection was built.
All of them failed.

Have a clue on it ?

Thanks in advance,

Matt

Depends on underlying transport. TCP and UDP do NOT buffer sends :slight_smile:

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “Matt Wu”
Newsgroups: ntdev
To: “Windows System Software Devs Interest List”
Sent: Friday, February 04, 2005 12:10 PM
Subject: [ntdev] xp tdi supprots ClientEventSendPossible ?

> Anyone has ever tried ClientEventSendPossible ?
> It always returns STATUS_INVALID_PARAMETER :frowning:
>
> It’s caused by “buffer sends” ? Anyone knows how to enable this feature ?
> I could not get any information about it from ddk documents.
>
> The same to the callback of TDI_EVENT_CHAINED_RECEIVE_EXPEDITE.
>
> I tried to set the two EventHandlers both before and after the connection was
built.
> All of them failed.
>
> Have a clue on it ?
>
> Thanks in advance,
>
> Matt
>
>
>
>
>
> —
> Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

Not supported: TDI_SERVICE_INTERNAL_BUFFERING is not set in ProviderInfo->ServiceFlags.

So this case we must issue synchronous TDI_SEND. But how will tdi process the
NON_BLOCKING transmit ?

Matt

“Maxim S. Shatskih” wrote:xxxxx@ntdev…
> Depends on underlying transport. TCP and UDP do NOT buffer sends :slight_smile:
>
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
> ----- Original Message -----
> From: “Matt Wu”
> Newsgroups: ntdev
> To: “Windows System Software Devs Interest List”
> Sent: Friday, February 04, 2005 12:10 PM
> Subject: [ntdev] xp tdi supprots ClientEventSendPossible ?
>
>
>> Anyone has ever tried ClientEventSendPossible ?
>> It always returns STATUS_INVALID_PARAMETER :frowning:
>>
>> It’s caused by “buffer sends” ? Anyone knows how to enable this feature ?
>> I could not get any information about it from ddk documents.
>>
>> The same to the callback of TDI_EVENT_CHAINED_RECEIVE_EXPEDITE.
>>
>> I tried to set the two EventHandlers both before and after the connection was
> built.
>> All of them failed.
>>
>> Have a clue on it ?
>>
>> Thanks in advance,
>>
>> Matt

> So this case we must issue synchronous TDI_SEND. But how will

tdi process the
NON_BLOCKING transmit ?

From what I remember, TCP ignores this.

TDI_SEND to TCP is pended till all ACKs will arrive for this portion.

This is obvious, since in case of packet loss TCP will need to retransmit, and
your “native” IRP’s MDL is the only source of data from which to retransmit.
TCP does not make any private copies of data of its own (this is the meaning of
“TCP is not a buffering transport TDI-wise”).

And, after all ACKs will arrive, no need in retransmitting the portion, so, TCP
can safely complete TDI_SEND.

Receive in TCP:

  • if TCP has pending TDI_RECEIVE IRPs - it fills them (from what I know, all
    but last are completely filled, the last is probably partially filled) and
    completes them.
  • after this, if TCP still has data in it - it calls ClientEventReceive,
    showing both the first contiguous chunk size, a pointer to it and the total
    data in TCP.
  • CER can do the following:
  • if BytesIndicated == BytesAvailable - receive all this data and return
    STATUS_SUCCESS
  • otherwise, receive BytesIndicated (there is a pointer to them), build a
    TDI_RECEIVE IRP to receive the rest of BytesAvailable, and return
    STATUS_MORE_PROCESSING_REQUIRED with this IRP. Do not forget to call
    IoSetNextIrpStackLocation on it.

If you want to apply the receiver-side backpressure - then return
STATUS_DATA_NOT_ACCEPTED from CER, this blocks further CER calls. After this,
to restart the data flow, you will mandatory need a TDI_RECEIVE IRP.

One of the possible approaches to TCP receive is:

  • the primary receiver is CER
  • it allocates the buffers of BytesAvailable size, and copies the lookahead
    there.
  • if buffer allocation failed due to hitting the limit (the total space in
    allocated buffers is limited as SO_RCVBUF option) - then return
    STATUS_DATA_NOT_ACCEPTED and mark the fact.
  • if lookahead does not cover the whole buffer - then a TDI_RECEIVE IRP is
    created and returned together with STATUS_MORE_PROCESSING_REQUIRED. The rest of
    the task is done in it’s completion routine.
  • otherwise, the full buffer is “put to list”.

Completion routine for TDI_RECEIVE also put the buffer to list.

The app’s recv() just consumes this list. If the list is empty, and if
STATUS_DATA_NOT_ACCEPTED was ever returned - it builds its own TDI_RECEIVE and
send it down to unfreeze the pipeline. First this TDI_RECEIVE will be
completed, delivering a buffer, then the usual CER mechanism will work.

This is how AFD works (I omitted the optimization when AFD uses the app’s
MDL from the app’s MJ_READ IRP instead of this buffer).
Other schemes are maybe also possible, which rely on TDI_RECEIVE more and
even have no CER.

To repeat the behaviour of the TDI transport:
a) if the data arrives and there is a TDI_RECEIVE at the head of the
pending list - it is satisfied with the data and completed. This step is
repeated till the list of pending TDI_RECEIVE will be empty.
b) after this, if the endpoint is not “stalled” and there is a CER
handler - CER is called.
c) at return from CER, the transport either have a command to set the
“stalled” flag (STATUS_DATA_NOT_ACCEPTED), or a direction to discard some
consumed data, or a new TDI_RECEIVE IRP.
d) the “stalled” flag is reset on each TDI_RECEIVE IRP arrival to the
dispatch routine.

Once more - CER is called only if there is no pending TDI_RECEIVE IRPs.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Maxim,

Thank you for your detailed directions.

Matt

“Maxim S. Shatskih” wrote:xxxxx@ntdev…
>> So this case we must issue synchronous TDI_SEND. But how will
>>tdi process the
>> NON_BLOCKING transmit ?
>
> From what I remember, TCP ignores this.
>
> TDI_SEND to TCP is pended till all ACKs will arrive for this portion.
>
> This is obvious, since in case of packet loss TCP will need to retransmit, and
> your “native” IRP’s MDL is the only source of data from which to retransmit.
> TCP does not make any private copies of data of its own (this is the meaning of
> “TCP is not a buffering transport TDI-wise”).
>
> And, after all ACKs will arrive, no need in retransmitting the portion, so, TCP
> can safely complete TDI_SEND.
>
> Receive in TCP:
>
> - if TCP has pending TDI_RECEIVE IRPs - it fills them (from what I know, all
> but last are completely filled, the last is probably partially filled) and
> completes them.
> - after this, if TCP still has data in it - it calls ClientEventReceive,
> showing both the first contiguous chunk size, a pointer to it and the total
> data in TCP.
> - CER can do the following:
> - if BytesIndicated == BytesAvailable - receive all this data and return
> STATUS_SUCCESS
> - otherwise, receive BytesIndicated (there is a pointer to them), build a
> TDI_RECEIVE IRP to receive the rest of BytesAvailable, and return
> STATUS_MORE_PROCESSING_REQUIRED with this IRP. Do not forget to call
> IoSetNextIrpStackLocation on it.
>
> If you want to apply the receiver-side backpressure - then return
> STATUS_DATA_NOT_ACCEPTED from CER, this blocks further CER calls. After this,
> to restart the data flow, you will mandatory need a TDI_RECEIVE IRP.
>
> One of the possible approaches to TCP receive is:
> - the primary receiver is CER
> - it allocates the buffers of BytesAvailable size, and copies the lookahead
> there.
> - if buffer allocation failed due to hitting the limit (the total space in
> allocated buffers is limited as SO_RCVBUF option) - then return
> STATUS_DATA_NOT_ACCEPTED and mark the fact.
> - if lookahead does not cover the whole buffer - then a TDI_RECEIVE IRP is
> created and returned together with STATUS_MORE_PROCESSING_REQUIRED. The rest of
> the task is done in it’s completion routine.
> - otherwise, the full buffer is “put to list”.
>
> Completion routine for TDI_RECEIVE also put the buffer to list.
>
> The app’s recv() just consumes this list. If the list is empty, and if
> STATUS_DATA_NOT_ACCEPTED was ever returned - it builds its own TDI_RECEIVE and
> send it down to unfreeze the pipeline. First this TDI_RECEIVE will be
> completed, delivering a buffer, then the usual CER mechanism will work.
>
> This is how AFD works (I omitted the optimization when AFD uses the app’s
> MDL from the app’s MJ_READ IRP instead of this buffer).
> Other schemes are maybe also possible, which rely on TDI_RECEIVE more and
> even have no CER.
>
> To repeat the behaviour of the TDI transport:
> a) if the data arrives and there is a TDI_RECEIVE at the head of the
> pending list - it is satisfied with the data and completed. This step is
> repeated till the list of pending TDI_RECEIVE will be empty.
> b) after this, if the endpoint is not “stalled” and there is a CER
> handler - CER is called.
> c) at return from CER, the transport either have a command to set the
> “stalled” flag (STATUS_DATA_NOT_ACCEPTED), or a direction to discard some
> consumed data, or a new TDI_RECEIVE IRP.
> d) the “stalled” flag is reset on each TDI_RECEIVE IRP arrival to the
> dispatch routine.
>
> Once more - CER is called only if there is no pending TDI_RECEIVE IRPs.
>
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com