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:


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]


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.

  • Do not confuse streams and packets, in a stream there is no guarantee that data will be delivered in the same chunks that it was sent, for this you would need a packet based protocol, not a stream based. – ctrl-alt-delor Feb 15 '15 at 20:53
  • that's precisely why I'm asking this question – M Conrad Feb 15 '15 at 20:56
  • The order should be preserved. That is what streams do. If a blocking read returns 0, then it is the end of the stream. If it returns another number then there may be more, you have to do at least one more read to find out. There is no such thing as message1, message2 etc. No message delimiter is transmitted. You have to add this to your protocol, if you need it. – ctrl-alt-delor Feb 17 '15 at 18:59
  • 1
    Specifically, I have a text-stream protocol and I'm adding a command which passes a file descriptor with a line of text. I need to know what order this ancillary data is received in relation to the text of the message in order to write the code properly. – M Conrad Feb 19 '15 at 6:15
  • 1
    @MConrad: I'd try to get a copy of the POSIX.1g specification. If it's not explicitly written there, then you may expect an implementation-specific behaviour. – Laszlo Valko Feb 24 '15 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.