what got broken in 2.2 kernels' TCP/IP?

martinsk (mkrikis@kenan.com)
Thu, 30 Sep 1999 21:40:24 -0400


I've been trying to port a little webserver to Linux and
can't find a solution to the following problem. Whenever
MSIE or Netscape ask for a cgi script with a POST method,
they get a "network error" when the socket gets closed.
No problems with the GET method (nor with the contents
returned by the script). While trying to identify
this, I've written the enclosed dummy server that
completely ignores all headers (thus treats GET and POST
the exact same way) and just sends back some headers (including
the content length) and 8 body bytes. This is like straight
out of networking textbooks, nothing fancy, as you can see.
It has the same problem with POST as the real server...

Strangely, this same code works fine with 2.0 kernels
or on HP, Sun, DEC machines. It must be something in the
kernel, since I've recompiled various kernels on this same
box; with 2.0 it works, with 2.2 doesn't (including
2.2.13pre14). Same exact code, no matter which library
linked with or whether dynamically or statically linked.
The only interface involved was loopback.

The problem shows if you access this server with POST from Netscape when it
is running on 2.2 kernels. lynx, KDE file manager
and simple telnet don't have a problem with me closing the
socket, but I need to get this working with Netscape
and Exploder. What's also strange is that a similar dummy server
written in Perl works fine with POST from Netscape.

Does anybody have an explanation for this? Suggestions?

Any input will be much appreciated.

Thanks,

Martins 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
}

-------------------------------------------------------------------

Post to the Dummy Server

-------------------------------------------------------------

I run it as
% ./dummyserver 8889

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