NetBSD-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: aligning control message ancillary data
After some further thought and discussion on other forums, I think
that I have worked out what the right usage is here. OpenBSD has a
man page for CMSG_DATA & friends, which on OpenBSD-current (but not
4.3) shows what the OpenBSD folks believe to be, and what I agree is,
the correct idiom. It would be very helpful, I think, if NetBSD had a
similar man page. Here is what I ought to have written in my first
message as the `correct' idiom (although it won't work on NetBSD
currently; see below for the two reasons):
struct msghdr msg;
struct cmsghdr *cmsg_ptr;
union {
struct cmsghdr align_me_please;
char data [CMSG_SPACE (sizeof (int))];
} control;
msg.msg_control = (void *) &control;
msg.msg_controllen = sizeof (control);
/* ... */
cmsg_ptr = CMSG_FIRSTHDR (&msg);
cmsg_ptr->cmsg_len = CMSG_LEN (sizeof (int));
NetBSD's CMSG_SPACE does not expand to a constant expression (nor does
CMSG_LEN). While one can allocate objects on the stack with
non-constant sizes, using C99 or alloca(3), this is very sketchy.
Hence monitor_fdpass.c does not do this. Instead...it picks a random
number that is hoped large enough for most people, and checks that it
is actually large enough at run-time. I have to wonder whether this
is really better than just dynamically allocating the control buffer.
Some (e.g., Theo) suggest that CMSG_SPACE and CMSG_LEN are wrong to
expand to non-constant expressions.
The other issue with the above code is that currently the NetBSD
kernel requires that the msg_controllen field of a msghdr be equal to
the cmsg_len field of the sole cmsghdr in the control buffer for
SCM_RIGHTS-type control messages. Thus if CMSG_SPACE (sizeof (int))
is not equal to CMSG_LEN (sizeof (int)) because of wider alignment
than what one finds on the i386, and you run the above code on NetBSD,
sendmsg will yield EINVAL. This, I believe, is wrong, and caused by
the following fragment from unp_internalize in kern/uipc_usrreq.c
starting on line 1292:
/* Sanity check the control message header. */
if (cm->msg_type != SCM_RIGHTS || cm->msg_level != SOL_SOCKET ||
cm->msg_len != control->m_len) /* <- This is the problem. */
return (EINVAL);
The OpenBSD developers who thoroughly scrutinized this several months
ago believe the kernel should check whether CMSG_ALIGN (cm->msg_len)
is inequal to control->m_len. But doing this might break a bunch of
existing code that used the incorrect yet working idiom. So in both
FreeBSD as of many years ago, and in OpenBSD-current as of a few
months ago, the analogous code checks whether cm->msg_len is simply
greater than control->m_len, which is clearly an error.
Home |
Main Index |
Thread Index |
Old Index