Bug 5437 - Sending with MSG_MORE causes data-loss.
Summary: Sending with MSG_MORE causes data-loss.
Status: REJECTED INVALID
Alias: None
Product: Networking
Classification: Unclassified
Component: IPV4 (show other bugs)
Hardware: i386 Linux
: P2 normal
Assignee: Stephen Hemminger
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-10-14 02:35 UTC by Sebastian Andersson
Modified: 2005-10-15 04:50 UTC (History)
0 users

See Also:
Kernel Version: 2.6.11
Subsystem:
Regression: ---
Bisected commit-id:


Attachments

Description Sebastian Andersson 2005-10-14 02:35:36 UTC
Most recent kernel where this bug did not occur:
Distribution: Debian
Hardware Environment: various x86
Software Environment: Tested under various versions of Debian GNU/Linux
Problem Description:

If there is some unread data in a socket and some data has been sent with the
MSG_MORE flag and the socket is closed, the MSG_MORE sent data isn't sent.

Steps to reproduce:

Compile this program, start it with a free TCP-port number and connect to that
port with telnet. Send 2 or more characters. The result should be "HI
THERE\r\n", but becomes "HI " on kernels with the bug.

-----------------------------8<---------------------------
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>

int
main(int argc, char **argv)
{
    struct sockaddr_in socket_addr;
    int fd = socket(PF_INET, SOCK_STREAM, 0);
    socklen_t len = sizeof(socket_addr);
    int on = 1;

    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
    memset(&socket_addr, 0, sizeof(socket_addr));
    socket_addr.sin_family = AF_INET;
    socket_addr.sin_port = htons(atoi(argv[1]));
    socket_addr.sin_addr.s_addr = INADDR_ANY;
    bind(fd, (struct sockaddr *) &socket_addr, sizeof(socket_addr));
    listen(fd, 1);
    fd = accept(fd, (struct sockaddr *) &socket_addr, &len);
    recv(fd, &on, 1, 0);
    send(fd, "HI ", 3, 0);
    send(fd, "THERE\r\n", 7, MSG_MORE);
    close(fd);
    sleep(5);
    return 0;
}
-----------------------------8<---------------------------
Comment 1 Andrew Morton 2005-10-14 02:44:56 UTC

Begin forwarded message:

Date: Fri, 14 Oct 2005 02:37:55 -0700
From: bugme-daemon@kernel-bugs.osdl.org
To: bugme-new@lists.osdl.org
Subject: [Bugme-new] [Bug 5437] New: Sending with MSG_MORE causes data-loss.


http://bugzilla.kernel.org/show_bug.cgi?id=5437

           Summary: Sending with MSG_MORE causes data-loss.
    Kernel Version: 2.6.11
            Status: NEW
          Severity: normal
             Owner: shemminger@osdl.org
         Submitter: bofh-reg-kernel-bug@diegeekdie.com


Most recent kernel where this bug did not occur:
Distribution: Debian
Hardware Environment: various x86
Software Environment: Tested under various versions of Debian GNU/Linux
Problem Description:

If there is some unread data in a socket and some data has been sent with the
MSG_MORE flag and the socket is closed, the MSG_MORE sent data isn't sent.

Steps to reproduce:

Compile this program, start it with a free TCP-port number and connect to that
port with telnet. Send 2 or more characters. The result should be "HI
THERE\r\n", but becomes "HI " on kernels with the bug.

-----------------------------8<---------------------------
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>

int
main(int argc, char **argv)
{
    struct sockaddr_in socket_addr;
    int fd = socket(PF_INET, SOCK_STREAM, 0);
    socklen_t len = sizeof(socket_addr);
    int on = 1;

    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
    memset(&socket_addr, 0, sizeof(socket_addr));
    socket_addr.sin_family = AF_INET;
    socket_addr.sin_port = htons(atoi(argv[1]));
    socket_addr.sin_addr.s_addr = INADDR_ANY;
    bind(fd, (struct sockaddr *) &socket_addr, sizeof(socket_addr));
    listen(fd, 1);
    fd = accept(fd, (struct sockaddr *) &socket_addr, &len);
    recv(fd, &on, 1, 0);
    send(fd, "HI ", 3, 0);
    send(fd, "THERE\r\n", 7, MSG_MORE);
    close(fd);
    sleep(5);
    return 0;
}
-----------------------------8<---------------------------

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.

Comment 2 Herbert Xu 2005-10-14 05:34:13 UTC
Andrew Morton <akpm@osdl.org> wrote:
> 
> If there is some unread data in a socket and some data has been sent with the
> MSG_MORE flag and the socket is closed, the MSG_MORE sent data isn't sent.

IMHO this is correct behaviour (although there may be a separate bug
in TCP, see below).

First of all MSG_MORE is a Linux-specific feature so we're not bound by
any standards.

More importantly, it makes sense to discard the data here.  The reason
is that MSG_MORE is telling the kernel to not send the data straight
away because you *will* make another send call later on to trigger the
transmission.

As you closed the socket without making another send call (or an ioctl
to the same effect), it would seem reasonable for the kernel to interpret
that as a desire to discard the data.

In fact, this behaviour is entirely consistent with the manual page
entry in send(2) about MSG_MORE:

       MSG_MORE (Since Linux 2.4.4)
              The caller has more data to send.  This flag is used with
              TCP sockets to obtain the same effect as the TCP_CORK socket
              option (see tcp(7)), with the difference that this flag
              can be set on a per-call basis.  Since Linux 2.6, this
              flag is also supported for UDP sockets, and informs the
              kernel to package all of the data sent in calls with this
              flag set into a single datagram which is only transmitted
              when a call is performed that does not specify this flag.

If you want to send the data as is you could execute an ioctl to
uncork the socket.  Alternatively, you should be able to do an
empty send(2) with MSG_MORE cleared to push the pending data out.

Actually, TCP seems to ignore an empty send(2) without MSG_MORE even
if there is pending data.  This looks like a bug to me.  Dave?

Cheers,
Comment 3 Sebastian Andersson 2005-10-14 06:17:38 UTC
If there is nothing to be read (connect to the testprogram's port with telnet
and just press ctrl-d), then all data will be sent to the client. So it is not
consistent from a servers point of view.

I think most people would expect MSG_MORE sent data to actually be sent without
having to perform an extra syscall before a close. At least I view MSG_MORE as a
performance increasing function (like TCP_CORK, but without having to add more
syscalls), not as a way to be able to avoid sending data before a close. Adding
an extra syscall before close to flush out MSG_MORE data lowers that performance
somewhat. I've not looked at the server code, but since the Nagle algorithm
already may have some data buffered-to-be-sent, I would suspect that
it would be almost costless to also check for MSG_MORE/CORKED data at
closing time.
Comment 4 Hideaki YOSHIFUJI 2005-10-14 06:22:27 UTC
In article <E1EQOnG-0006O6-00@gondolin.me.apana.org.au> (at Fri, 14 Oct 2005 22:36:14 +1000), Herbert Xu <herbert@gondor.apana.org.au> says:

> Andrew Morton <akpm@osdl.org> wrote:
> > 
> > If there is some unread data in a socket and some data has been sent with
> the
> > MSG_MORE flag and the socket is closed, the MSG_MORE sent data isn't sent.
> 
> IMHO this is correct behaviour (although there may be a separate bug
> in TCP, see below).
:
> More importantly, it makes sense to discard the data here.  The reason
> is that MSG_MORE is telling the kernel to not send the data straight
> away because you *will* make another send call later on to trigger the
> transmission.
> 
> As you closed the socket without making another send call (or an ioctl
> to the same effect), it would seem reasonable for the kernel to interpret
> that as a desire to discard the data.

I second this. I don't think current behavior is buggy.

--yoshfuji
Comment 5 Anonymous Emailer 2005-10-14 06:59:54 UTC
Reply-To: dada1@cosmosbay.com

Andrew Morton a 
Comment 6 Anonymous Emailer 2005-10-14 13:49:34 UTC
Reply-To: davem@davemloft.net

From: YOSHIFUJI Hideaki / $B5HF#1QL@(B <yoshfuji@linux-ipv6.org>
Date: Fri, 14 Oct 2005 22:24:28 +0900 (JST)

> I second this. I don't think current behavior is buggy.

I also agree.

All we've shown is that the test program is buggy :-)

To answer Herbert's other query, I think it is wrong to
handle a zero length non-MSG_MORE request after MSG_MORE.
The user should clear MSG_MORE when there is in fact no
more data to send.

So in essence, "NOTABUG", and let's move on :-)


Note You need to log in before you can comment on or make changes to this bug.