Failing to receive message with MSG_OOB

2014-07-16 Thread Vincent Gross
Hi folks,

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 ?

Thnaks for your time

--
Vincent / dermiste

[demime 1.01d removed an attachment of type application/pgp-signature]



Re: Failing to receive message with MSG_OOB

2014-07-16 Thread Philip Guenther
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