closing a socket causes problems---why?

closing a socket causes problems---why?

Post by mkri.. » Sat, 25 Sep 1999 04:00:00



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

The problem shows if you access it with POST from Netscape when it
is running on 2.2.5-15 kernel (tried both with glibc 2.1.6
and 2.0.7). No problem on 2.0.34 kernel at home or on
HP, Sun, DEC. No problem with lynx, telnet to it, KDE file manager.
No problem if Netscape uses GET method. No problem for a very
similar dummy server written in Perl.

Can somebody please tell me what might be causing this? Did
something get broken in kernel between 2.0 and 2.2? Is it something
with certain glibc versions? Am I just missing something?
Is there any workaround known?

Any input will be much appreciated.

Thanks,


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

#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

Quote:}