/*

Byte Stream Connection Server Example
-------------------------------------

  The server end is much more complicated.  Since we want to allow
multiple clients to be connected to the server at the same time, it
would be incorrect to wait for input from a single client by simply
calling `read' or `recv'.  Instead, the right thing to do is to use
`select' (*note Waiting for I/O::.) to wait for input on all of the
open sockets.  This also allows the server to deal with additional
connection requests.

  This particular server doesn't do anything interesting once it has
gotten a message from a client.  It does close the socket for that
client when it detects an end-of-file condition (resulting from the
client shutting down its end of the connection).

*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT    21
#define MAXMSG  512

int read_from_client (int filedes)
{
   char buffer[MAXMSG];
   int nbytes;

   nbytes = read (filedes, buffer, MAXMSG);
   if (nbytes < 0) {
       /* Read error. */
       perror ("read");
       exit (EXIT_FAILURE);
   }
   else if (nbytes == 0)
       /* End-of-file. */
       return -1;
   else {
       /* Data read. */
       fprintf (stderr, "Server: got message: `%s'\n", buffer);
       return 0;
   }
}


int main (void)
{
   extern int make_socket (unsigned short int port);
   int sock;
   fd_set active_fd_set, read_fd_set;
   int i;
   struct sockaddr_in clientname;
   size_t size;

   /* Create the socket and set it up to accept connections. */
   sock = make_socket (PORT);
   if (listen (sock, 1) < 0) {
       perror ("listen");
       exit (EXIT_FAILURE);
   }

   /* Initialize the set of active sockets. */
   FD_ZERO (&active_fd_set);
   FD_SET (sock, &active_fd_set);

   while (1) {
       /* Block until input arrives on one or more active sockets. */
       read_fd_set = active_fd_set;
       if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) {
           perror ("select");
           exit (EXIT_FAILURE);
       }

       /* Service all the sockets with input pending. */
       for (i = 0; i < FD_SETSIZE; ++i) {
           if (FD_ISSET (i, &read_fd_set)) {
               if (i == sock) {
                   /* Connection request on original socket. */
                   int new;
                   printf("incoming connect\n");
                   size = sizeof (clientname);
                   new = accept (sock,
                      (struct sockaddr *) &clientname, &size);
                   if (new < 0) {
                       perror ("accept");
                       exit (EXIT_FAILURE);
                   }
                   fprintf (stderr,
                       "Server: connect from host %s, port %hd.\n",
                       inet_ntoa (clientname.sin_addr),
                   ntohs (clientname.sin_port));
                   FD_SET (new, &active_fd_set);
               } else {
                   /* Data arriving on an already-connected socket. */
                   if (read_from_client (i) < 0) {
                        close (i);
                        FD_CLR (i, &active_fd_set);
                   }
               }
           }
       }
   }
}