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

#define PORT    5555
#define MAXMSG  512

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

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

int
main (void)
@{
  extern int make_socket (uint16_t port);
  int sock;
  fd_set active_fd_set, read_fd_set;
  int i;
  struct sockaddr_in clientname;
  socklen_t size;

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

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

  while (1)
    @{
      /* @r{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);
        @}

      /* @r{Service all the sockets with input pending.} */
      for (i = 0; i < FD_SETSIZE; ++i)
        if (FD_ISSET (i, &read_fd_set))
          @{
            if (i == sock)
              @{
                /* @r{Connection request on original socket.} */
                int new;
                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
              @{
                /* @r{Data arriving on an already-connected socket.} */
                if (read_from_client (i) < 0)
                  @{
                    close (i);
                    FD_CLR (i, &active_fd_set);
                  @}
              @}
          @}
    @}
@}
