[comp.protocols.tcp-ip] STREAMS flow control in SunOS 4.1.1

thomas@nexus.se (06/27/91)

I've converted an application using a TCP socket to talk to a remote process
to use STREAMS instead. The communication is half duplex, the connection is
established and a lot of data is sent to the remote end and a reply is
expected after the remote end has consumed the data.

When I've set up the connection I I_PUSH tirdwr (after I_POPing timod)
to be able to use the ordinary read / write system calls. 
If I'm using sockets there wont be more than a few K bytes on the way
before write blocks. Using STREAMS I find that write will 
never block, I can cram 150K down the stream without blocking. The problem is
that I seem to lose the last part of the data. Also data flowing from the 
remote end is lost. Using a lanwatcher I can see that the last part of the
data written is not transmitted and that the remote end actually sends data 
that is never delivered to the process.

I would like the behaviour of the stream to match that of a socket. 
What am I missing? Is there an option that can be used on the stream that
would limit the amount of data that is on the way before blocking 
or is it a bug in SunOS?


--
Real life:      Thomas Tornblom             Email:  t_tornblom@nexus.se
Snail mail:     Communicator Nexus          Phone:  +46 18 171814
                Box 857                     Fax:    +46 18 696516
                S - 751 08 Uppsala, Sweden

robert@netsoft.wimsey.bc.ca (Robert B. Nelson) (06/28/91)

In <THOMAS.91Jun27102100@mozart.nexus.se> thomas@nexus.se writes:

>When I've set up the connection I I_PUSH tirdwr (after I_POPing timod)
>to be able to use the ordinary read / write system calls. 

The problem is I_POPing timod, don't do it!  "tirdwr" translates the calls
between the stream head and "timod", if you pop "timod" then the streams driver
or mux which is next in the stream gets "timod" messages that it doesn't know
how to deal with.

>If I'm using sockets there wont be more than a few K bytes on the way
>before write blocks. Using STREAMS I find that write will 
>never block, I can cram 150K down the stream without blocking. The problem is
>that I seem to lose the last part of the data. Also data flowing from the 
>remote end is lost. Using a lanwatcher I can see that the last part of the
>data written is not transmitted and that the remote end actually sends data 
>that is never delivered to the process.

Flow control is handled within "timod" which you've removed.

>I would like the behaviour of the stream to match that of a socket. 
>What am I missing? Is there an option that can be used on the stream that
>would limit the amount of data that is on the way before blocking 
>or is it a bug in SunOS?


>--
>Real life:      Thomas Tornblom             Email:  t_tornblom@nexus.se
>Snail mail:     Communicator Nexus          Phone:  +46 18 171814
>                Box 857                     Fax:    +46 18 696516
>                S - 751 08 Uppsala, Sweden
-- 
Robert B. Nelson                               NetSoft Systems Inc
Phone: (604) 261-3652                          1102 West 48th Avenue
INTERNET: robert@netsoft.wimsey.bc.ca          Vancouver, BC, CANADA, V6M 2N5

hwajin@sgi.com (Hwa-jin Bae) (06/28/91)

>>>>> On 27 Jun 91 09:21:00 GMT, thomas@nexus.se said:

thomas> When I've set up the connection I I_PUSH tirdwr (after
thomas> I_POPing timod) to be able to use the ordinary read / write
thomas> system calls.  If I'm using sockets there wont be more than a
thomas> few K bytes on the way before write blocks.

it's not clear what's meant by "blocking" here but if you're refering
to a case where the call to write() blocks when socket level buffer
is full you can get around the problem by setsockopt()'ing with
larger number for socket level buffers.  the size available depend on the
upper limit for the amount of mbuf your kernel allowed for
such allocation. some systems have limit set to 64K even though the
default size of socket level buffer for a given protocol is set to
much smaller "a few" K bytes.

thomas> Using STREAMS I find that write will never block, I can cram
thomas> 150K down the stream without blocking. The problem is that I
thomas> seem to lose the last part of the data. Also data flowing from
thomas> the remote end is lost. Using a lanwatcher I can see that the
thomas> last part of the data written is not transmitted and that the
thomas> remote end actually sends data that is never delivered to the
thomas> process.

since the tirdwr simply calls tpi multiplexor in most implementations,
and hands over STREAMS msg to put routine of the tpimux, and tpimux
has its own write-put-service  routine, data loss at the STREAMS
msg queue between modules is probably unlikely.  sounds like a
protocol implementation strangeness... a few things to check:
1) how many bytes are not delivered, 2) anything still queued
at the socket on the sending side? (use netstat), 3) does write()
return successfully, 4) check tcp window sizes (sender might be
zero win probing) using your analyzer, 5) check # of bytes
not received on the receive side and the contents, 6) look at the
contents of last 20 or so tcp segments snooped via the net analyzer.

*hwajin
--
protocol engines, inc.

hwajin@sgi.com (Hwa-jin Bae) (06/29/91)

>>>>> On 28 Jun 91 00:08:15 GMT, robert@netsoft.wimsey.bc.ca (Robert B. Nelson) said:

Robert> The problem is I_POPing timod, don't do it!  "tirdwr"
Robert> translates the calls between the stream head and "timod", if
Robert> you pop "timod" then the streams driver or mux which is next
Robert> in the stream gets "timod" messages that it doesn't know how
Robert> to deal with.

on output side "tirdwr" simply hands over data to downstream (do putnext()),
unless the size is 0 (as documented in the manual), in which case it
discards it, while filtering out M_PROTO and M_PCPROTO msg's.

on input side "tirdwr" does various things with M_PROTO/M_PCPROTO msg's,
handling data, expedited data indication, orderly release, and disconnect
indication in the way described in the manaul.

there's really isn't any translation being done inside "tirdwr".
"timod" and "tirdwr" provide distinct services by handling disjoint
set of messages.  if you're not doing any further protocol
specific stuff and simply doing write()/read() on the end point,
it's shouldn't matter whether you have "timod" below tirdwr or not,
although i haven't personally tried to do it this way.  most people
just push "tirdwr" on a descriptor returned by t_open() directly,
which means on top of "timod".

Robert> Flow control is handled within "timod" which you've removed.

"timod" doesn't really do any flow control.  the place flow control
happens (in most implementations) is below or at tpimux level.  usually
by the protocols themselves if they're capable.




just my $.02.




*hwajin
--
protocol engines, inc.