From owner-freebsd-hackers Fri Jan 10 13:07:48 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.4/8.8.4) id NAA03010 for hackers-outgoing; Fri, 10 Jan 1997 13:07:48 -0800 (PST) Received: from home.winc.com (mgessner@home.winc.com [204.178.182.2]) by freefall.freebsd.org (8.8.4/8.8.4) with ESMTP id NAA02986 for ; Fri, 10 Jan 1997 13:07:28 -0800 (PST) Received: (from mgessner@localhost) by home.winc.com (8.8.4/8.8.4) id QAA23987 for hackers@freebsd.org; Fri, 10 Jan 1997 16:05:56 -0500 Message-Id: <199701102105.QAA23987@home.winc.com> Subject: bind(2): address already in use -- how to fix? To: hackers@freebsd.org (FreeBSD Hackers) Date: Fri, 10 Jan 1997 16:05:55 -0500 (EST) From: mgessner@aristar.com Organization: Aristar Software Development, Inc. Reply-To: mgessner@aristar.com X-Mailer: ELM [version 2.4 PL24] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk 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 #include #include #include #include #include #include #include #include #include #include #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 , Computer Scientist Aristar, Inc. 302 N. Cleveland-Massillon Rd. Akron, OH 44333 (330) 668-2267, (330) 668-2961 FAX