For the shut_rd case, I think a cleaner impl is to send RST *only* if there is pending data (received but not read by the user) or new data is received after the read end is closed. At the moment I don't recall what BSD does but you don't have to allow draining once the read end is closed. Just drain and RST! Any user reads should fail.
I recall having to deal with this in the past while working on a packet level network proxy. No access to that code now so the above is from memory. Sent from my iPad > On Feb 3, 2017, at 5:56 PM, Skip Tavakkolian <skip.tavakkol...@gmail.com> > wrote: > > Has anyone looked into implementing this? Can anyone comment on the details? > > For the curious, this is described here: > https://tools.ietf.org/html/rfc1122#page-87 > Go net package (https://github.com/golang/go/issues/17906). > > As I understand it, one would only worry about 'shutdown' if the connection > is in 'Established' state. It is not clear to me what the state should > transition to when the read-end is closed (i.e. shut_rd). Also, there > doesn't not seem to be consistency between different implementations > (Windows,Linux, *BSD) on what should happen to what's already in the read > queue; should it be allowed to drain to the reader or discarded immediately? > > Shutting down the write-end (i.e. 'shut_wr'), should send FIN, and transition > to Finwait1. > > I think the correct mechanics to handle this would be to add two new messages > in tcpctl (/sys/src/9/ip/tcp.c). Then, roughly something like this: > > case 'shut_rd' : > if (Etablished) { > qhangup(rq); > send(RST); // Windows does this and RFC1122 seems to recommend it. Linux > does not. > tcb->rcv.blocked = 1; // all that's needed? > tcb->rcv.wnd = 0; > tcpsetstate(????) // not sure what it should be or should stay Established? > } > > case 'shut_wr': > if (Established) { > qhangup(wq); > send(FIN) > tcpsetstate(Finwait_1) > } > >