I noticed that in the 2.2 kernel, pending connections
are not always accepted in the order in which they were initiated.
In many cases, one would never notice, but when there are
many connections transferring a small amount of data one-way,
the out-of-order reception can be a surprise.  I don't know what
is officially correct, but it certainly differs from the 2.0 behavior.

I have two programs that look like this:

ipread:
        s1 = socket(...)
        bind(s1,...)
        listen(s1,5)
        while(1)
                s2 = accept(s1,...)
                read(s2,buf,...)
                write(1,buf,...)
                close(s2)



ipwrite:
        while fgets(...,buf,stdin)!=NULL
                s = socket(...)
                connect(s,...)
                write(s,buf,...)
                close(s)


The real code is included below, in this message, 134 lines combined.

I run these programs like this:

        ipread 6666 &
        nl /etc/passwd  | ./ipwrite localhost:6666

I should then see the lines of /etc/passwd, numbered.
There are extraordinary delays (several seconds) every 5-10 lines,
and sometimes the lines are printed out of order.

Workarounds include gross things (e.g., sending some bogus data back),
as well as using SO_LINGER or adding "shutdown(s,1);read(s,...);"
to the writer before each close.  Is something like this "more correct"?

My question is not so much how to get it working, but
 A) whether there is a kernel bug, and
 B) what is the "best" portable solution?

I'm running RH5.2 + kernel 2.2.0 on intel, without much else in the way of
changes.  The problem does not occur in 2.0 kernels.

Thanks,
Jan Edler
[EMAIL PROTECTED]

------------------------ start of ipread.c --------------------------
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>


/* listen on a specified port, and for each connection, copy the stuff to stdout */

int
main (int argc, char **argv)
{
        char *progname;
        char lbuf[1000];
        int port;
        int ret;
        int sl, sp;                     /* listen and peer sockets */
        struct sockaddr_in addrl, addrp;/* listen and peer addresses */
        int lenp;                       /* peer addr length */

        progname = argv[0];
        if (argc != 2) {
                fprintf (stderr, "Usage: %s port\n", progname);
                return 1;
        }
        port = atoi(argv[1]);

        sl = socket (AF_INET, SOCK_STREAM, 0);
        if (sl < 0) {
                fprintf (stderr, "%s: socket: %s\n", progname, strerror(errno));
                return 2;
        }
        addrl.sin_family = AF_INET;
        addrl.sin_addr.s_addr = htonl(INADDR_ANY);
        addrl.sin_port = htons(port);
        if (bind(sl, (struct sockaddr *)&addrl, sizeof(addrl)) < 0) {
                fprintf (stderr, "%s: bind: %s\n", progname, strerror(errno));
                return 2;
        }
        if (listen(sl, 5) < 0) {
                fprintf (stderr, "%s: listen: %s\n", progname, strerror(errno));
                return 2;
        }
        while (1) {
                lenp = sizeof(addrp);
                sp = accept (sl, (struct sockaddr *)&addrp, &lenp);
                if (sp < 0) {
                        fprintf (stderr, "%s: accept: %s\n", progname, 
strerror(errno));
                        continue;
                }

                while ((ret = read (sp, lbuf, sizeof(lbuf))) > 0)
                        write (1, lbuf, ret);
                if (ret < 0)
                        fprintf (stderr, "%s: read: %s\n", progname, strerror(errno));
                close (sp);
        }
}
------------------------ end of ipread.c --------------------------
------------------------ start of ipwrite.c --------------------------
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>


/* copy from stdin to a specified host:port, each line separately */

int
main (int argc, char **argv)
{
        char *progname;
        char buf[1000];
        char *host;
        int port;
        int s;
        int errs = 0;
        struct sockaddr_in addr;
        struct hostent *hp;

        progname = argv[0];
        if (argc != 2) {
usage:          fprintf (stderr, "Usage: %s host:port\n", progname);
                return 1;
        }
        host = strchr (argv[1], ':');
        if (host == NULL)
                goto usage;
        *host++ = 0;
        port = atoi(host);
        host = argv[1];

        hp = gethostbyname (host);
        if (hp == NULL) {
                fprintf (stderr, "%s: can't get address for %s\n", progname, host);
                return 1;
        }
        memset (&addr, 0, sizeof(addr));
        addr.sin_family = hp->h_addrtype;
        if (hp->h_length <= 0 || hp->h_length > sizeof(addr.sin_addr)) {
                fprintf (stderr, "%s: bad address length for %s\n", progname, host);
                return 1;
        }
        memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
        addr.sin_port = htons(port);

        while (fgets (buf, sizeof(buf), stdin) != NULL) {
                s = socket (AF_INET, SOCK_STREAM, 0);
                if (s < 0) {
                        fprintf (stderr, "%s: socket: %s\n", progname, 
strerror(errno));
                        errs = 2;
                }
                else if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                        fprintf (stderr, "%s: connect: %s\n", progname, 
strerror(errno));
                        close(s);
                        errs = 2;
                }
                else if (write (s, buf, strlen(buf)) < 0) {
                        fprintf (stderr, "%s: write: %s\n", progname, strerror(errno));
                        errs = 2;
                }
                if (s>=0)
                        close (s);
        }
        return errs;
}
------------------------ end of ipwrite.c --------------------------
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to [EMAIL PROTECTED]

Reply via email to