--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/