In the example I give: ... message_buffer[0] = 'F'; io_vector[0].iov_base = message_buffer; io_vector[0].iov_len = 1;
memset(&msg, 0, sizeof(struct msghdr)); msg.msg_iov = io_vector; msg.msg_iovlen = 1; ... msg.msg_iov would be NULL with a memset. msg.msg_iovlen likely specifies how many are in the msg.msg_iov array. Can the code be fixed to not cause problems when msg.msg_iov is zero? At first blush, that would seem like a simple fix to me. I assume that such a fix wouldn't break POSIX or some RFC. On Sun, Apr 2, 2017 at 7:59 AM Otto Moerbeek <[email protected]> wrote: > On Sun, Apr 02, 2017 at 12:29:05PM +0000, Luke Small wrote: > > > Maybe before it is sent, iov_len can be defaulted to 0 in the example, > > since it'd take an initializer like in c++ to do it otherwise(wanna put > c++ > > in the base! Lol). I assume it wouldn't try to read a zero length > iov_base. > > The problem may be that usually iov_len has a nonzero value, but the base > > points to a bad location, when it isn't specified by the user program. > > On Sun, Apr 2, 2017 at 7:05 AM Otto Moerbeek <[email protected]> wrote: > > msg is zero'd, so the iov data in fields are initialized. > > -Otto > > > > > > On Sat, Apr 01, 2017 at 10:57:48AM +0000, Luke Small wrote: > > > > > > > Or put in the man page to "Google it!" Lol > > > > On Sat, Apr 1, 2017 at 5:33 AM Otto Moerbeek <[email protected]> wrote: > > > > > > > > > On Sat, Apr 01, 2017 at 12:50:46AM -0700, Philip Guenther wrote: > > > > > > > > > > > On Sat, 1 Apr 2017, Otto Moerbeek wrote: > > > > > > > On Sat, Apr 01, 2017 at 01:20:25AM -0500, Luke Small wrote: > > > > > > > > > > > > > > > Here are two programs. They both fork two clients that try to > > > connect > > > > > > > > on port 'portno' that is listened to in main(). It spawns a > > > receive > > > > > > > > that receives passed file descriptors passed from main(). It > > > passes a > > > > > > > > file descriptor of the client connection to receive twice. > > > > > > > > server_sample0.c uses the man page code. server_sample.c > uses my > > > > > > > > example. the former fails to pass the file descriptor on the > > > second > > > > > > > > try. the latter succeeds both times. I don't think you have > any > > > more > > > > > > > > questions. > > > > > > > > > > > > > > Well, it took some effort to get this out of you. > > > > > > > > > > > > > > It seems that a problem exists indeed. It happens when the > iovec > > > data > > > > > is > > > > > > > not filled in, as the example uses. recv(2) only returns the > > > number of > > > > > > > bytes read from the iovec, so there seems to be some confusion > > > about a > > > > > > > failed read and a read of zero bytes. I'll check with the > standard > > > what > > > > > > > is supposed to happen when only auciliary data is sent. > > > > > > > > > > > > Well, it's not a failed read: recvmsg() returns 0, not -1. > > > > > > > > > > Indeed, my wording was wrong. Still, on the receving side, you > like to > > > > > dsitinguish beteen -1, 0 (EOF) and a real message, I suppose. > > > > > > > > > > > > > > > > > The issue is that in the kernel socket receive buffer, control > > > messages > > > > > > from a single send are always followed by a normal data buffer. > In > > > > > kernel > > > > > > terms, an MT_CONTROL mbuf chain is always followed by an MT_DATA > mbuf > > > > > > chain...even when there's no data sent. In that case, the > MT_DATA > > > mbuf > > > > > > has length zero. > > > > > > > > > > > > This works fine on the sending side, but when recvmsg() finishes > > > with the > > > > > > control messages and gets to the data buffer, it thinks it's > done, > > > as the > > > > > > caller requested that nothing be copied out and it doesn't > remove the > > > > > > zero-length MT_DATA mbuf, leaving it at the head of the socket > > > buffer. > > > > > > Succeeding calls see no control messages at the start and then > again > > > do > > > > > > nothing to the data buffer. > > > > > > > > > > > > Note this is specific to SOCK_STREAM sockets: the boundary > preserving > > > > > > behavior of SOCK_DGRAM and SOCK_SEQPACKET mean it doesn't happen > > > there. > > > > > > > > > > > > To avoid this, the application doesn't need to *send* any data, > it > > > just > > > > > > needs to always accept at least one byte of data when calling > > > recvmsg(). > > > > > > Even if there's no data there, that acceptance of more than zero > > > bytes of > > > > > > data will let recvmsg() peel off the zero-length MT_DATA mbuf > from > > > the > > > > > > send. > > > > > > > > > > > > > > > > > > I guess the questions then are > > > > > > 1) is this a bug? can it be fixed? and > > > > > > 2) if not, should it be documented and where? > > > > > > > > > > > > On the latter, I'm not convinced the example code in > CMSG_DATA(3) is > > > the > > > > > > place to do so. If we deleted all the EXAMPLES sections from > > > manpages > > > > > > they should be merely more difficult to understand, not > incomplete. > > > More > > > > > > importantly, this behavior isn't related to the CMSG_* macros at > > > all, but > > > > > > rather to recvmsg(2) itself. Maybe a cavest there? > > > > > > > > > > I'd say, it's a bug, but if it cannot be fixed for some reason, > > > > > recvmsg(2) should document this *and* the example in CMSG_DATA(3) > > > should > > > > > show the proper use. > > > > > > > > > > > > > > > -Otto > > > > > > > > > > > > > > > > Relevant to this discussion (thangs jca@ fro pointing this out!) is > > > this old thread: > > > http://marc.info/?l=openbsd-tech&m=140008704815878&w=2 > > > > > > The table in one of the messages (look at in raw mode) show that many > > > operating systems have problems with this case. > > > > > > So a CAVEAT entry in recvmsg(2) and the example showing the portable > > > way of doings things are still needed, whether the bug will be fixed in > > > OpenBSD or not. > > > > > > As I read it, sendmsg(2) with no data is fine according to the > standard: > > > > > > quote from http://pubs.opengroup.org/onlinepubs/9699919799/ : > > > > > > The msg_iov and msg_iovlen fields of message specify zero or > more > > > buffers containing the data to be sent. msg_iov points to an > array > > > of > > > iovec structures; msg_iovlen shall be set to the dimension of > this > > > array. In each iovec structure, the iov_base field specifies a > > > storage > > > area and the iov_len field gives its size in bytes. Some of > these > > > sizes can be zero. The data from each storage area indicated by > > > msg_iov is sent in turn. > > > > > > Alas, the standard is not clear about a recvmsg(2) call with no data > > > buffer space. > > > > > > -Otto > > > >
