On Wed, 16 Jul 2014, Vincent Gross wrote:
I am trying to observe the effect of MSG_OOB while receiving data.
I have a small demo program that creates an accepting socket, connect a
sending socket to the accepting, closes the accepting socket to keep
only the sending and the receiving, forks, and handle receive on the
parent and send on the child. No flags of any kinds are set.
write(send_sk, (void *)payload, sizeof(payload)) /
read(recv_sk, (void *)payload, sizeof(payload)) = no problem.
sendto(send_sk, (void *)payload, sizeof(payload), 0, NULL, 0) /
recvfrom(recv_sk, (void *)payload, sizeof(payload), 0, NULL, 0) = no
problem.
sendto(send_sk, (void *)payload, sizeof(payload), MSG_OOB, NULL, 0) /
recvfrom(recv_sk, (void *)payload, sizeof(payload), 0, NULL, 0) =
fails with errno = 0, and tcpdump shows me the packet with the URG flag
set.
sendto(send_sk, (void *)payload, sizeof(payload), MSG_OOB, NULL, 0) /
recvfrom(recv_sk, (void *)payload, sizeof(payload), MSG_OOB, NULL, 0)
= fails with EINVAL on the receiving end, and tcpdump shows me the
packet with the URG flag set.
Did I miss something on the man pages ? or is it something more sinister ?
The behavior of MSG_OOB is somewhat subtle; I would strongly recommend
UNIX Network Programming, Vol 1, by W. Richard Stevens, which has a good
chapter on this. This is something missing from our manpages currently,
including an extra meaning for EINVAL return from recv*.
In this case, the key item is that TCP MSG_OOB is really an 'urgent'
marker which points to a position in the stream. By default, the receiver
will save the indicated byte (just one!) in a separate buffer for fetching
with MSG_OOB, but only after the non-urgent data before it has been
received. If do a MSG_OOB send of multiple bytes, it's really treated as
a normal send of all but the final byte, followed by MSG_OOB send of that
final byte; recv(MSG_OOB) will fail with error EINVAL until you first read
the earlier, non-urgent data. After that, you can use ioctl(SIOCATMARK)
to determine whether there's a byte of urgent data to read with
recv(MSG_OOB) or just more normal data.
An example of how to use SIOCATMARK, recv(MSG_OOB), and POLLRDBAND to
detect when the sending side has sent new urgent data can be found in
usr.bin/telnet/sys_bsd.c, though it has some historical baggage to handle
ancient kernels that you shouldn't copy. Really, the book is the place to
go at this point...
(sigh, two more items for the todo list: manpage additions and telnet
cruft removal)
Philip