NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/54435: reading TCP urgent data with MSG_OOB doesn't clear poll(2) status



The following reply was made to PR kern/54435; it has been noted by GNATS.

From: Robert Elz <kre%munnari.OZ.AU@localhost>
To: Valery Ushakov <uwe%stderr.spb.ru@localhost>
Cc: gnats-bugs%netbsd.org@localhost
Subject: Re: kern/54435: reading TCP urgent data with MSG_OOB doesn't clear poll(2) status
Date: Thu, 08 Aug 2019 10:19:08 +0700

     Date:        Thu, 8 Aug 2019 04:21:46 +0300
     From:        Valery Ushakov <uwe%stderr.spb.ru@localhost>
     Message-ID:  <20190808012146.GC1102%pony.stderr.spb.ru@localhost>
 
   | See my previous reply to the PR.
 
 Yes, I saw that after I sent my reply (... not that it really
 matters, but just as an explanation - I was reading backwards
 through the messages ... that way I see what has been answered
 before I see the questions which means I don't need to think
 about whether I should attempt an answer in many cases) - your
 two messages were close together, with the same Subject (just
 like happened this time) - and I just assumed that (like happened
 this time) there was one copy sent via gnats, and another to either
 one of the lists, or direct to me, so I just skipped the earlier one 
 initially, but then noticed it later).
 
 Your point in it that it is entirely possible that no-one has ever
 written a poll/select application that deals with MSG_OOB with TCP
 without using SO_OOBINLINE is probably correct though.  Not that it
 should really matter, as no-one should be writing TCP applications
 that use OOB without setting SO_OOBINLINE in the receiver.  It simply
 is the wrong way.
 
   | and then calls poll with POLLIN|POLLPRI to decide what to do next, it
   | will end up in an busy-wait loop as poll will immediately return
   | POLLPRI (only), but recv(MSG_OOB) will fail, then the receiver calls
   | poll and the loop repeats.
 
 That looks like a bug somewhere - certainly in code that would do
 a recv(), get an EINVAL, and then repeat the same recv() again (regardless
 of an intervening poll()) - but it is possible the kernel also has a
 bug, that one I would need to look into more closely to see why that
 "no more data" is an issue.
 
   | Aside - I wonder if the notion of "at mark" made sense for those other
   | protocols that had real out of band data (of which I know nothing).
 
 Not really, as best I recall them.   I am fairly certain it would be
 meaningless for X.25, which had OOB data, but there was no way the
 receiver could know (from its transport protocol - or network layer
 protcol it would usually be called, there was just one - that is
 not considering anything that application protcol may have layered
 on top) how much regular data the sender had queued before it sent
 the OOB data.   OOB (just one packet permitted until that was ack'd)
 was sent outside all of the normal sequencing and flow control rules
 (which is why it is called "out of band").
 
 Whether OSI TP had any mechanism to mark where in the regular packet
 stream an OOB packet was sent I have no idea, I never looked at it in
 enough detail to pick up on that kind of nuance.
 
 This also indicates something of an oddity in the development of all
 of this in BSD ... the API was designed to cope with OSI (which at the
 time was a plausible mass use protocol - or its advocates thought so
 anyway) but the only procotol implemented (at the time) which could be
 used to test any of this was TCP, so while the API looks like it was
 designed for OOB data, it was really only ever (initially) used with
 urgent data.
 
   | It's also not entirely obvious to me what given POLLIN | POLLRDBAND
   | the right action is to read/drain the normal (in band) stream first.
 
 It is the nature of TCP.   Despite what the BSD API seems to promise,
 the urgent data cannot be guaranteed to be delivered until all previous
 data has been read.   What's more, and also despite the apparent API,
 an application could do
 
 	send("a"); send("b"); send("c", MSG_OOB);
 
 where the whole combination "abc" is intended to be urgent - it doesn't
 send the OOB flag until the end, as until then all the urgent data isn't
 available, it doesn't want the received to read to "b" and assume it
 has all of it, so the urgent pointer should never be there.
 
 Remember that all there is is data, and a "mark" that says, "somewhere
 before here there is data that the application protocol needs to see
 and process before it processes other data that is arriving earlier".
 There is also just one mark - if the application sends more urgent data
 the mark just moves further down the stream - the earlier urgent data
 is still there in the queue, but is no longer marked any way (the sender
 might know where it is, but has no (TCP) way to convey that to the
 recipient, the receiver cannot keep track of all the various urgent
 data pieces, as there's no guarantee anything will be sent to it at all
 in between 2 OOB writes from the sender.  That is, if my example had
 been
 
 	send("a", MSG_OOB); send("b"); send("c", MSG_OOB);
 
 (and no more MSG_OOB) we know the receiver will get the urgent
 pointer after "c", but the one after "a" might never have been
 sent to it - the sending TCP sees both, but after the "c" OOB
 has been queued, has no way to convey the earlier "a" mark to the
 receiver - there is just one urgent pointer and it is now after "c".
 
   | This is likely highly application and protocol dependent,
 
 Absolutely.   The application has to provide some design for
 what data should be sent as urgent, and how the receiver is to
 recognise that.   Further to do that, the application has to know
 exactly what its transport prococol provices.   For TCP transport
 telnet has all this done properly.  rlogin is simply a mess.
 
 There is simply no way to write a transport protocol agnostic
 application which uses any kind of out of band or urgent data.
 
   | but it would
   | seem natural to want to read real out of band data out of band,
 
 Yes, it would - but TCP has no such concept.  There is no out of band
 data.  If you don't understand that, you cannot sanely attempt to use
 MSG_OOB with a TCP transport.
 
   | i.e. calling recv(MSG_OOB) as soon as POLLRDBAND is reported.
 
 You can do that - and various hacks that are in the sockets TCP
 stack sometimes pretend to allow it to work.   But it is all nonsense,
 nothing in TCP makes any of the attempts to do that meaningful in any
 way at all, which is why not using SO_OOBINLINE with a TCP transport
 is simply crazy.
 
   | So I'm
   | somewhat worried that we are imposing the semantic of TCP not-really
   | OOB urgent data - which happens to be the only user of this interface
   | - on the way that interface behaves.
 
 It all depends upon what the transport procotol implements.   Since we
 currently have nothing but TCP (and SCTP, just in case that is different,
 though I doubt it - but as I recall it does keep record markers rather than
 just providing a byte stream, so it might be) it is all very hard to tell
 what might happen with a transport protocol that actually has OOB data
 (I never once used either X.25 or OSI procotocls on a BSD system - I had
 my own X.25 once, but it was all imolemented in a plug in board, the system
 just saw something not all that much different to a modem - can make calls,
 transport bytes, and hang up... which is just what applications like uucp
 wanted to be able to do.)
 
 But I would not be surprised if you are somewhat correct.   TCP is all that
 existed to be used for testing when all this was developed (the others came
 later) and is all that exists again now (the others have vanished again).
 Until we get another implemented transport protocol which supports genuine
 OOB data, we will probably never really know.   When do you expect one of
 those?
 
 kre
 
 


Home | Main Index | Thread Index | Old Index