Re: TdiBuildReceive question
- From: "Maxim S. Shatskih" <maxim@xxxxxxxxxxxxxxxx>
- Date: Thu, 31 Aug 2006 06:36:13 +0400
if the connection is ESTABLISH state. However, I meet
it in the real
world, e.g. Irp->IoStatus.Status = STATUS_SUCCESS,
Irp->IoStatus.Information < the size of the buffer.
TCPIP completes the TDI_RECEIVE IRP in the following cases:
1) the IRP's buffer is full
2) the packet with PSH flag arrived
3) some (3 seconds?) timeout expired, and the IRP's buffer has at least 1 byte.
So, the behavior you observe is OK.
The idea under this is the following: it is desirable to minimize the number of
syscalls made by the app, so, if the app calls recv() with the large buffer,
then it is better to fill it as much as possible, and not complete the recv()
with, say, 1 byte - it is legal, but sub-performing.
So, TCPIP does its best to fill the IRP completely. Nevertheless, there can be
a time gap in data flow due to sender's behavior. For such a case, there is 3
second timeout, after which recv() will be completed with as many bytes as
currently received.
Losing 3 seconds on such a case is not so acceptable, in fact, only acceptable
as a last resort. To prevent such a time loss, the TCP protocol has a PSH bit
in the packets. PSH means - "the sender does not know when the next bytes will
follow", and forces the receiver to complete the recv() ASAP.
Normal TCP senders set PSH on the last packet in send(). If the single send()
call is splitted by TCP sender to several packets - then PSH is only set in the
last of them. If not splitted - then it is just set. This allows the receiver
to accumulate these packets in a single recv() and minimize the number of
syscalls - around one recv() per one send(), not one recv() per packet.
Nevertheless, if the sender is lame and never sends PSH - then this will cause
3second timeout on most recv() calls, which is not acceptable.
To bypass this, AFD has the AfdIgnorePushBitOnReceives registry parameter,
which should only be set if there are known lame senders which do not set PSH.
Without this parameter, AFD submits the large buffers to TCPIP - and yes, with
the lame sender, they will be hanging inside TCPIP till fully completed or till
3 seconds.
With this parameter, AFD only submits the receive sizes which were already
indicated to ClientEventReceive - this guarantees that all recv() calls from
the app to AFD will be completed ASAP just after the very first packet arrival.
The dark side of this parameter is that it switches off this optimization of
reducing the number of syscalls, so, it should only be used with lame senders
who do not support PSH.
Also note: it is always a good idea to only submit the TDI_RECEIVE IRP from
ClientEventReceive, by returning this IRP as OUT parameter to
ClientEventReceive. The only other place to submit TDI_RECEIVE is - to restart
the receiver after you have returned STATUS_DATA_NOT_ACCEPTED from
ClientEventReceive - this blocks the later ClientEventReceive calls. IIRC AFD
works exactly this way, with the size in TDI_RECEIVE being influenced by the
above-described parameter.
OK, here is the link to one more topic on this subject:
http://www.osronline.com/showThread.cfm?link=26257
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim@xxxxxxxxxxxxxxxx
http://www.storagecraft.com
.
- Follow-Ups:
- Re: TdiBuildReceive question
- From: hanzhu
- Re: TdiBuildReceive question
- References:
- TdiBuildReceive question
- From: hanzhu
- TdiBuildReceive question
- Prev by Date: Re: Winsock layered hook driver as a gateway
- Next by Date: Re: PLX PCI9656 driver developing problem
- Previous by thread: TdiBuildReceive question
- Next by thread: Re: TdiBuildReceive question
- Index(es):
Relevant Pages
|