Ancillary data is received as if it were queued along with the first normal data octet in the segment (if any).
-- POSIX.1-2017
For the rest of your question, things get a bit hairy.
...For the purposes of this section, a datagram is considered to be a data segment that terminates a record, and that includes a source address as a special type of ancillary data.
Data segments are placed into the queue as data is delivered to the socket by the protocol. Normal data segments are placed at the end of the queue as they are delivered. If a new segment contains the same type of data as the preceding segment and includes no ancillary data, and if the preceding segment does not terminate a record, the segments are logically merged into a single segment...
A receive operation shall never return data or ancillary data from more than one segment.
So modern BSD sockets exactly match this extract. This is not surprising :-).
Remember the POSIX standard was written after UNIX, and after splits like BSD v.s. System V. One of the main goals was to help understand the existing range of behaviour, and prevent even more splits in existing features.
Linux was implemented without reference to BSD code. It appears to behave differently here.
If I read you correctly, it sounds like Linux is additionally merging "segments" when a new segment does include ancillary data, but the previous segment does not.
Your point 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", does not seem entirely explained by the standard. One possible explanation would involve a race condition. If you read part of a "segment", you will receive the ancillary data. Perhaps Linux interpreted this as meaning the remainder of the segment no longer counts as including ancillary data! So when a new segment is received, it is merged - either as per the standard, or as per difference 1 above.
If you want to write a maximally portable program, you should avoid this area altogether. When using ancillary data, it is much more common to use datagram sockets. If you want to work on all the strange platforms that technically aspire to provide something mostly like POSIX, your question seems to be venturing into a dark and untested corner.
You could argue Linux still follows several significant principles:
- "Ancillary data is received as if it were queued along with the first normal data octet in the segment".
- Ancillary data is never "concatenated", as you put it.
However, I am not convinced the Linux behaviour is particularly useful, when you compare it to the BSD behaviour. It seems like the program you describe would need to add a Linux-specific workaround. And I don't know a justification for why Linux would expect you to do that.
It might have looked sensible when writing the Linux kernel code, but without ever having been tested or exercised by any program.
Or it might be exercised by some program code which mostly works under this subset, but in principle could have edge-case "bugs" or race conditions.
If you cannot make sense of the Linux behaviour and its intended usage, I think that argues for treating this as a "dark, untested corner" on Linux.
You're confusing two things here.
A socket is a file descriptor - a handle - given to a program so that it can use a network connection in almost the same way it uses files. The socket API is protocol-independent; sockets can be created for IPv4 connections or IPv6 ones, but (given kernel support) also for things like DECnet, AppleTalk, or read Ethernet.
Since the socket API is fairly easy to use but since talking to a process on the same machine using an actual network protocol is rather inefficient, at some point the UNIX domain socket was created to allow use of the socket API without that inefficiency. It also adds some extra features; e.g., it is possible to pass file descriptors to another process over a UNIX domain socket.
When one uses UNIX domain sockets, both processes still hold a socket, one for each side of the connection. The use of the socket is no different from, say, IPv4 sockets, apart from the initial connection setup.
One thing the socket API cannot do without is an address; it is not possible to create a socket without passing it an address to talk to, and this is no different for the UNIX domain socket. Since it's UNIX, where everything is a file anyway, it was decided to make these addresses look like filenames. And since we're already doing that, it makes sense to make these addresses appear in the file system, since that makes it easy to spot them.
Unfortunately, the name given to these things in the file system was also 'UNIX domain socket' (or at least, that's what people started calling them). They're not the actual sockets in the sense of the socket API, however; they couldn't be, since those are just a number. As such, their counterpart in an IPv4 socket is not that number, but instead the IP address and port number of the peer you're talking to.
Occasionally, I'll add that since the socket API doesn't deal with files directly, these filesystem representations aren't strictly necessary. Indeed, Linux has a concept of 'anonymous UNIX domain sockets', which are just that: UNIX domain sockets without any link in the filesystem...
Best Answer
Unix sockets are reliable. If the reader doesn't read, the writer blocks. If the socket is a datagram socket, each write is paired with a read. If the socket is a stream socket, the kernel may buffer some bytes between the writer and the reader, but when the buffer is full, the writer will block. Data is never discarded, except for buffered data if the reader closes the connection before reading the buffer.