Re: socket close() weirdness in 2.2 kernels

Sam Gendler (sam.gendler@software.com)
Tue, 05 Oct 1999 12:15:59 -0700


This one is simple. You are posting 0 bytes of data, but the posted data is terminated
with another "\r\n", so you have an extra 2 bytes of data on the socket that you are not
reading. Try sending a GET request to the same application and you shouldn't need the
extra 2 bytes of reading, since the request will terminate after the first empty line. By
the way, it is incorrect to not include the \r in your returned headers. All clients
support it due to a fair number of applications that do this, but it isn't correct.

--sam

Martins Krikis wrote:

> My apologies for continuing about the same thing, but IMHO
> the matters didn't get explained or resolved previously.
>
> Most everybody said I'm not reading all the data, but I am!
>
> This is about the dummy-webserver code (enclosed at the end),
> that reads all headers and sends the response. Doing another
> read after the headers returns 0 (IMHO meaning that there is
> no more data (at least yet)). When the server does a close(),
> Netscape or Exploder report a "Network Error", if they had
> accessed server with a POST request.
>
> According to Alan Cox, "Linux 2.2 sends a reset to indicate
> to the other end that you shut down without reading
> all the sent data". Like I said, this is all the data
> (as the enclosed HTTP headers will testify), and further
> read()-s return 0 (and I'm afraid they may block one day).
> So the first question is, what's really going on there?
> Note that these same browsers have no problem with this server
> code running on 2.0 kernels or on Solaris, HPUX or OSF1.
>
> If Linux 2.2 really sends a reset, why would it do so when I
> actually have read all the data?
>
> However, like I wrote before, I am thankful for the previous responses,
> because I've found a kludge now. An ugly one, IMO, but something.
> Basically, if before doing close() the server does a read() for
> at least 2 characters (or 2 reads for 1 character), the problem
> disappears. But all these reads still return 0 (and may block, right?),
> so there was no data to read. Why would they make any difference?
> And why wouldn't a single read() for just 1 character?
>
> And finally, what should I do to solve the problem decently?
> I can't believe I really have to do a useless read() for 2 characters
> when I know well that there is no more data. (Plus, I'd have to
> take care of possible blocking.)
>
> I would very much like to understand what's going on and you are
> the only people who can explain this, so please help me.
>
> Thank you very much,
>
> Martin mkrikis@kenan.com
>
> ------------------------------------------------------------------------------
>
> #include <stdlib.h>
> #include <stdio.h>
> #include <errno.h>
> #include <string.h>
> #include <unistd.h>
> #include <netinet/in.h>
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <arpa/inet.h>
>
> #define LINELEN 1023
>
> int main(int argc, char **argv)
> {
> int port = 0, on = 1, s, fd, i, j, l;
> char line[LINELEN + 1];
> struct sockaddr_in sa;
> /* struct linger ls; */
> char msg[] = "HTTP/1.0 200 OK\n"
> "Content-Type: text/plain\n"
> "Content-Length: 8\n"
> "\n"
> "abcdefg\n";
>
> if (argc >= 2)
> port = atoi(argv[1]);
>
> if (!port)
> port = 8080;
>
> memset(&sa, 0, sizeof(struct sockaddr_in));
> sa.sin_port = htons(port);
> sa.sin_family = AF_INET;
>
> if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
> {
> perror("socket");
> exit(1);
> }
>
> if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)))
> perror("setsockopt");
>
> /* This doesn't help either
>
> ls.l_onoff = 1;
> ls.l_linger = 500;
>
> if (setsockopt(s, SOL_SOCKET, SO_LINGER, (const void *) &ls, sizeof(ls)))
> perror("setsockopt");
> */
>
> if (bind(s, (struct sockaddr *) (void *) &sa, sizeof(struct sockaddr_in))
> < 0)
> {
> perror("bind");
> exit(2);
> }
>
> if (listen(s, SOMAXCONN))
> {
> perror("listen");
> exit(3);
> }
>
> printf("Listening on port %d\n", port);
>
> for ( ; ; )
> {
>
> if ((fd = accept(s, NULL, NULL)) < 0)
> {
> perror("accept");
> exit(4);
> }
>
> printf("Accepted a connection on fd %d\n", fd);
>
> for ( ; ; ) // reading all the headers here
> {
>
> for (i = 0; i < LINELEN; i++)
> {
>
> if (read(fd, line + i, 1) < 0)
> {
> perror("read");
> exit(5);
> }
>
> if (line[i] == '\n')
> {
> line[i + 1] = '\0';
> printf("Just input: %s", line);
> break;
> }
>
> }
>
> if (i >= LINELEN)
> {
> printf("Line longer than %d\n", LINELEN);
> exit(6);
> }
>
> if (!strcmp(line, "\n") || !strcmp(line, "\r\n"))
> break;
>
> }
>
> l = strlen(msg);
>
> for (i = 0; i < l; i += j)
> if ((j = write(fd, msg + i, l - i)) < 0)
> {
> perror("write");
> exit(7);
> }
>
> if (close(fd) < 0)
> {
> perror("close");
> exit(8);
> }
>
> }
>
> return 0; // not reached
> }
>
> ---------------------------------------------------------------------------
>
> <html>
>
> <head>
> <title>Post to the Dummy Server</title>
> </head>
>
> <body bgcolor="#FDE0CE">
>
> <FORM method="POST" action="http://localhost:8889">
>
> <input type="submit" value="post to the dummy server on localhost:8889">
>
> </FORM>
> </body>
> </html>
>
> ------------------------------------------------------------------------
>
> $ ./dummyserver 8889
> Listening on port 8889
> Accepted a connection on fd 8
> Just input: POST / HTTP/1.0
> Just input: Referer: http://localhost:8000/localdummy.html
> Just input: Connection: Keep-Alive
> Just input: User-Agent: Mozilla/4.61 [en] (X11; U; Linux 2.2.13pre14 i586)
> Just input: Host: localhost:8889
> Just input: Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
> Just input: Accept-Encoding: gzip
> Just input: Accept-Language: en
> Just input: Accept-Charset: iso-8859-1,*,utf-8
> Just input: Content-type: application/x-www-form-urlencoded
> Just input: Content-length: 0
> Just input:
>
> ---------------------------------------------------------------------
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.rutgers.edu
> Please read the FAQ at http://www.tux.org/lkml/

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/