So I've read lots of information on unix-stream ancillary data, but one thing missing from all the documentation is what is supposed to happen when there is a partial read?
Suppose I'm receiving the following messages into a 24 byte buffer
msg1 [20 byes] (no ancillary data)
msg2 [7 bytes] (2 file descriptors)
msg3 [7 bytes] (1 file descriptor)
msg4 [10 bytes] (no ancillary data)
msg5 [7 bytes] (5 file descriptors)
The first call to recvmsg, I get all of msg1 (and part of msg2? Will the OS ever do that?) If I get part of msg2, do I get the ancillary data right away, and need to save it for the next read when I know what the message was actually telling me to do with the data? If I free up the 20 bytes from msg1 and then call recvmsg again, will it ever deliver msg3 and msg4 at the same time? Does the ancillary data from msg3 and msg4 get concatenated in the control message struct?
While I could write test programs to experimentally find this out, I'm looking for documentation about how ancillary data behaves in a streaming context. It seems odd that I can't find anything official on it.
I'm going to add my experimental findings here, which i got from this test program:
https://github.com/nrdvana/daemonproxy/blob/master/src/ancillary_test.c
Linux 3.2.59, 3.17.6
It appears that Linux will append portions of ancillary-bearing messages to the end of other messages as long as no prior ancillary payload needed to be delivered during this call to recvmsg. Once one message's ancillary data is being delivered, it will return a short read rather than starting the next ancillary-data message. So, in the example above, the reads I get are:
recv1: [24 bytes] (msg1 + partial msg2 with msg2's 2 file descriptors)
recv2: [10 bytes] (remainder of msg2 + msg3 with msg3's 1 file descriptor)
recv3: [17 bytes] (msg4 + msg5 with msg5's 5 file descriptors)
recv4: [0 bytes]
BSD 4.4, 10.0
BSD provides more alignment than Linux, and gives a short read immediately before the start of a message with ancillary data. But, it will happily append a non-ancillary-bearing message to the end of an ancillary-bearing message. So for BSD, it looks like if your buffer is larger than the ancillary-bearing message, you get almost packet-like behavior. The reads I get are:
recv1: [20 bytes] (msg1)
recv2: [7 bytes] (msg2, with msg2's 2 file descriptors)
recv3: [17 bytes] (msg3, and msg4, with msg3's 1 file descriptor)
recv4: [7 bytes] (msg5 with 5 file descriptors)
recv5: [0 bytes]
TODO:
Would still like to know how it happens on older Linux, iOS, Solaris, etc, and how it could be expected to happen in the future.