Hi,
I use unix domain datagram sockets for IPC, e.g. I receive messages by
calling recv().
"man 2 recv" tells me about the flags argument to a recv() call, namely:
MSG_TRUNC
Return the real length of the packet, even when it was longer
than the passed buffer. Only valid for packet sockets.
Thus I used recv() with flags MSG_TRUNC|MSG_PEEK in order to detect
message truncation due to insufficient buffer size.
Strangely enough, MSG_TRUNC seems to get ignored by the kernel: If the
message received is larger than the receive buffer I supplied, the
function returns the size of the buffer. I think, the function should
return the real message length instead (at least according to the manual
page).
To work around this problem, I now use the ioctl FIONREAD instead.
On the other hand, in this mailing list, I found an old bug report
describing the same problem using UDP sockets:
http://groups.google.com/group/fa.linux.kernel/browse_frm/thread/fb6acbb527507e26/ad0b2ba33b6b66fa
UDP sockets seem to have been patched by now. From linux/net/ipv4/udp.c:
udp_recvmsg()
...
err = copied;
if (flags & MSG_TRUNC)
err = skb->len - sizeof(struct udphdr);
...
Why doesn't unix_dgram_recvmsg() in linux/net/unix/af_unix.c contain code
to this effect? Is this a feature or a bug? What is the correct semantics
of MSG_TRUNC when used for unix sockets?
Cheers
Daniel Kabs
PS: According to some lkml archives, my previous mail did not come
through, so I reposted it.
From: Daniel Kabs <[email protected]>
Date: Mon, 29 Jan 2007 12:59:49 +0100
> I use unix domain datagram sockets for IPC, e.g. I receive messages by
> calling recv().
>
> "man 2 recv" tells me about the flags argument to a recv() call, namely:
>
> MSG_TRUNC
> Return the real length of the packet, even when it was longer
> than the passed buffer. Only valid for packet sockets.
>
> Thus I used recv() with flags MSG_TRUNC|MSG_PEEK in order to detect
> message truncation due to insufficient buffer size.
What part of "Only valid for packet sockets" from the manual page
escapes you? :-))
It's a feature which only was meant to be valid for AF_PACKET sockets.
What UDP is doing is different, it's returning the full packet length
when the packet is larger then the given buffer size, but it does this
irregardless of whether you set MSG_TRUNC in the recvmsg() passed-in
flags. UDP itself sets the MSG_TRUNC flag when it detects this
situation.
I checked the history and our AF_UNIX sockets have always behaved like
this.
On Monday 05 February 2007 01:52, David Miller wrote:
> > Thus I used recv() with flags MSG_TRUNC|MSG_PEEK in order to detect
> > message truncation due to insufficient buffer size.
>
> What part of "Only valid for packet sockets" from the manual page
> escapes you? :-))
> It's a feature which only was meant to be valid for AF_PACKET sockets.
Thanks for pointing that out. I thought, "packet sockets" means
"datagram-oriented socket". Obviously it means PF_PACKET instead. It's
hard to learn programming IPC by only reading man pages :-)
> What UDP is doing is different, it's returning the full packet length
> when the packet is larger then the given buffer size, but it does this
> irregardless of whether you set MSG_TRUNC in the recvmsg() passed-in
> flags. UDP itself sets the MSG_TRUNC flag when it detects this
> situation.
Please correct me gently if I am wrong: According to the kernel source
code, this behaviour was introduced with patch-2.6.8:
http://www.kernel.org/diff/diffview.cgi?file=/pub/linux/kernel/v2.6/patch-2.6.8.gz;z=4325
linux/net/ipv4/udp.c
+
err = copied;
+ if (flags & MSG_TRUNC)
+ err = skb->len - sizeof(struct udphdr);
I think local sockets (PF_UNIX) implement a different semantics: According
to unix_dgram_recvmsg() in linux/net/unix/af_unix.c, in case of
truncation the buffer size is returned and not the full packet length.
In my opinion this implementation of local sockets (PF_UNIX) is not
following the wording of the man page man 2 recv: "These calls return
the number of bytes received". Am I getting something wrong here?
Why not improve consistency and make unix_dgram_recvmsg() return the full
packet length? So it would behave as UDP does. What do you think about
adding the following code to linux/net/unix/af_unix.c:
err = size;
+ if (flags & MSG_TRUNC)
+ err = skb->len;
Cheers
Daniel
> Why not improve consistency and make unix_dgram_recvmsg() return the full
> packet length? So it would behave as UDP does. What do you think about
> adding the following code to linux/net/unix/af_unix.c:
It would be nice if the world worked that way, but you can't break POSIX
compliance. Perhaps another receive flag?
DS
On Tuesday 06 February 2007 21:11, David Schwartz wrote:
> > Why not improve consistency and make unix_dgram_recvmsg() return the
> > full packet length? So it would behave as UDP does. What do you think
> > about adding the following code to linux/net/unix/af_unix.c:
>
> It would be nice if the world worked that way, but you can't break
> POSIX compliance. Perhaps another receive flag?
I now understand that setting the MSG_TRUNC flag is only applicable for
PF_PACKET. I do not argue about that any more. :-)
What I question is the return value when receiving from a local socket
using recv(). Sorry, I don't know what the POSIX standard has to say
about receiving from local sockets in contrast to UDP sockets as my only
reference are the man pages.
According to "man 2 recv", on success the return value is the "the number
of bytes received". Since patch-2.6.8, UDP is always returning the full
packet length. I'd like to see local sockets (PF_UNIX) to do the same.
Does POSIX stipulate a different behaviour for local sockets?
Cheers
Daniel
On Monday 05 February 2007 01:52, David Miller wrote:
> What UDP is doing is different, it's returning the full packet length
> when the packet is larger then the given buffer size, but it does this
> irregardless of whether you set MSG_TRUNC in the recvmsg() passed-in
> flags. UDP itself sets the MSG_TRUNC flag when it detects this
> situation.
I hope that I am researching the appropriate kernel source tree, but if I
am not mistaken, this behaviour was introduced with change 1.66 according
to bitkeeper:
http://linux.bkbits.net:8080/linux-2.6/net/ipv4/udp.c?PAGE=history
I think the bitkeeper comment on that change (1.66) is misleading:
"[UDP]: Return true length if user specifies MSG_TRUNC."
As you said, this is wrong. The true length is returned, regardless
whether the user specified MSG_TRUNC.
Exploring this topic I learned a lot about browsing and reading kernel
source code, e.g. that commit statements have to be taken with a grain of
salt :-)
Cheers
Daniel