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

