Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Jan 1997 16:05:55 -0500 (EST)
From:      mgessner@aristar.com
To:        hackers@freebsd.org (FreeBSD Hackers)
Subject:   bind(2): address already in use -- how to fix?
Message-ID:  <199701102105.QAA23987@home.winc.com>

next in thread | raw e-mail | index | archive | help
Hello, all,

	I'm doing some what I think to be VERY straightforward server
code.  I call socket(), bind(), listen() and then accept().  I am
binding to a constant port number, so that my clients will always know
where to connect.

	If the descriptor returned by accept() is valid, I call fork,
close the original descriptor returned by socket(), and then start my 
processing in the child.  In the child, I use read(2) and write(2) to
communicate, and when all done, call close(2) on the new socket to close
the connection, and then call exit().

	I have a SIG_CHLD handler set up, so that I can watch the
termination.  Now something funny happens:

	in sig_chld, I get reported to me several pids that WERE NOT
the result of a fork() call by the server.  Why is this?

	Also, when I terminate my program when a child has not closed
its socket because the client has crashed, if I try to restart my server I 
get the error message:

	"Address already in use"

	I do have a SIG_INT handler defined, and in it, I check the
child pid value (0 or non-zero).  If it's zero, I close the child's
socket, else I close the parent's socket.

	I'm pretty confused about this whole problem.  It doesn't seem
to me that this should be so difficult, and the syntax for setting these
sockets for client/server access are pretty well known.  I do have a
copy of Stevens' Unix Network Programming that I'm using, but that
doesn't seem to help too much.

	This problem causes me to have to reboot my machine, which is very
undesirable.  Can someone please shed some light on this?  I've attached
a copy of my source.  Thanks in advance.

	Matt Gessner <mgessner@aristar.com>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>

#define K 1024

char *pkgdir;

/* spit out a list of all the files in the pkgdir via sockfd */
void pkglist (int sockfd)
{
  FILE *p;
  char buf[32 * K], name[32];

  sprintf (buf, "ls %s", pkgdir);

  p = popen (buf, "r");

  strcpy (buf, "[");
  while (! feof (p)) {
    fscanf (p, "%s\n", name);
    strcat (buf, "\"");
    strcat (buf, name);
    strcat (buf, "\",");
  }
  strcat (buf, "]\n");

  writec (sockfd, buf, strlen (buf), 3);
}

/* return a text file 'pkgname' in pkgdir. via sockfd */
void pkggett (int sockfd, const char *pkgname)
{
  int f;
  char fbuf[128], c;
  int len, w = 0;

  sprintf (fbuf, "%s/%s", pkgdir, pkgname);
  if ((f = open (fbuf, O_RDONLY)) > 0) {
    while ((len = read (f, (void *) fbuf, 128)) > 0) {
      w = write (sockfd, fbuf, len);
    }
    c = 3;
    write (sockfd, &c, 1);
    close (f);
  }
  else {
    fprintf (stderr, "error opening %s\n", fbuf);
  }
}

/* return a binary file 'pkgname' via sockfd */
void pkgget (int sockfd, const char *pkgname)
{
  int f;
  char fbuf[128], c;
  int len, w = 0;

  sprintf (fbuf, "%s/%s", pkgdir, pkgname);
  if ((f = open (fbuf, O_RDONLY)) > 0) {
    while ((len = read (f, (void *) fbuf, 128)) > 0) {
      w = write (sockfd, fbuf, len);
    }
    close (f);
  }
  else {
    fprintf (stderr, "error opening %s\n", fbuf);
  }
}

/* the main child command loop.  
   accepts commands via sockfd and sends the appropriate response. */
void pkgsrv (int sockfd)
{
  char cmd[64];
  int done = 0, len;

  while (! done) {
    if ((len = readc (sockfd, cmd, sizeof cmd, 3)) > 0) {
      fprintf (stderr, "my pid is %d\n", getpid());
      fprintf (stderr, "command is %s\n", cmd);
      if (strncasecmp (cmd, "list", 4) == 0) {
        pkglist(sockfd);  
      }
      else if (strncasecmp (cmd, "gett ", 5) == 0) {
        pkggett (sockfd, (char *) &cmd[5]);
      }
      else if (strncasecmp (cmd, "get ", 4) == 0) {
        fprintf (stderr, "sending package %s\n", &cmd[4]);
        pkgget (sockfd, (char *) &cmd[4]);
        fprintf (stderr, "sent package %s\n", &cmd[4]);
      }
      else if (strncasecmp (cmd, "quit", 4) == 0) {
        done = 1;
      }
      else {
        fprintf (stderr, "received unrecognized command: %s\n", cmd);
      }
    }
    else {
      done = 1;
    }
  }
}

int sockfd, newsockfd, childpid;

void sig_int ()
{
  fprintf (stderr, "terminating on SIGINT\n");
  if (childpid != 0) {
    close (sockfd);
  }
  else {
    close (newsockfd);
  }
  exit (-1);
}

void sig_chld ()
{
  int pid, status;

/* sometimes this returns a pid which was not created via the fork() below */
  while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
    fprintf (stderr, "child %d terminating, status = %08x\n", pid, status);
}

void main (int argc, char *argv[])
{
  int clilen;
  struct sockaddr_in serv_addr, cli_addr;

  if (argc == 2) {

    signal (SIGINT, sig_int);
    signal (SIGCHLD, sig_chld);

    /* set the pkgdir pointer */
    pkgdir = argv[1];

    /* Get a socket. */
    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
      err_sys ("socket error");
    }

    /* bind the socket to a named port */
    bzero ((char *) &serv_addr, sizeof serv_addr);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons (54321);

    if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof serv_addr) < 0) {
      err_sys ("bind error");
    }

    /* listen for requests for connection on the socket */
    listen (sockfd, 5);

    for ( ; ; ) {
      /* accept a connection request */

      fprintf (stderr, "Waiting for connection on port %d\n", 
        htons (serv_addr.sin_port));

      clilen = sizeof cli_addr;
      newsockfd = accept (sockfd, (struct sockaddr *) &cli_addr, &clilen);

      fprintf (stderr, "connection established with %s on port %d\n", 
        inet_ntoa (cli_addr.sin_addr), htons (cli_addr.sin_port));

      if (newsockfd < 0) {
        err_sys ("accept error");
      }

      if ((childpid = fork()) < 0) {
        err_sys ("fork error");
      }
      else if (childpid == 0) {
        close (sockfd);
        pkgsrv (newsockfd);
        close (newsockfd);
        fprintf (stderr, "closing connection with %s on port %d\n", 
          inet_ntoa (cli_addr.sin_addr), htons (cli_addr.sin_port));
        exit (0);
      }
      else {
        fprintf (stderr, "spawned child process %d\n", childpid);
        close (newsockfd);
      }
    }
  }
  else {
    fprintf (stderr, "usage: %s pkgdir\n", argv[0]);
    exit (1);
  }
}

--
Matthew Gessner <mgessner@aristar.com>, Computer Scientist
Aristar, Inc.
302 N. Cleveland-Massillon Rd.
Akron, OH 44333
(330) 668-2267, (330) 668-2961 FAX



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199701102105.QAA23987>