#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>

/*
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
*/

#define PORT    5555
#define MAXMSG  512


int  main (void)
{

   int make_socket (uint16_t port);
   int sock;
   fd_set active_fd_set, read_fd_set;
   int i;
   struct sockaddr_in clientname;
   size_t size;

   /* Crea el socket y se pone en estado de escucha para aceptar conecciones. */
    sock = make_socket (PORT);
    if (listen (sock, 1) < 0)
    {
         perror ("listen");
         exit (EXIT_FAILURE);
    }

    /* Inicializa el conjunto de sockets (file descriptors). */
    FD_ZERO (&active_fd_set);  //pone a cero bits
    FD_SET (sock, &active_fd_set);  //configura el bit para el fd socket a 1 
    
    while (1)
    {
      /* bloquea el programa hasta que la entrada este lista sobre un determinado fd_set(sockets). */
      /* la entrada esta lista cuando hay conecciones pendientes que pueden ser aceptadas*/
      /*espera por una nueva entrada para realizar una nueva conneccion o para utilizar una existente*/
      /*espera por el cambio de estado del fd_set */ 	     
       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)
        /*revisa si el bit de posicion i  que representa al fd es 1 en el fd_set*/
	/*procesa solo los sockets(fd) configurados a 1*/      
	if (FD_ISSET (i, &read_fd_set))
        {
          /*entrada que solicita una conneccion sobre el socket del servidor
	    el estado de sock a cambiado */		
          if (i == sock) 
          {
            
            int new;
            size = sizeof (clientname);
            /*acepta la coneccion*/
	    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
	  {
	    /* cuando la entrada es sobre un socket ya abierto. */
	    if (read_from_client(i) < 0)
	    {
	      close (i);
	      FD_CLR (i, &active_fd_set);
	    }
	  }
        }//cierra if FD_ISSET
    }//cierra while
}//cierra main



int  make_socket (uint16_t port)
{
     int sock;
     struct sockaddr_in name;


     /* Creacion del socket fd. */
     sock = socket (PF_INET, SOCK_STREAM, 0);
     if (sock < 0)
     {
        perror ("socket");
        exit (EXIT_FAILURE);
     }
     /* Give the socket a name. */
     name.sin_family = AF_INET;
     name.sin_port = htons (port);
     name.sin_addr.s_addr = htonl (INADDR_ANY);

     if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
     {
           perror ("bind");
           exit (EXIT_FAILURE);
     }

     return sock;
}



int  read_from_client (int filedes)
{
     char buffer[MAXMSG];
     int nbytes;
     /*lee MAXMSG bytes del fd (socket) filedes y lo copia a buffer
       devuelve el numero de bytes leidos  */
     nbytes = read(filedes, buffer, MAXMSG);
     if (nbytes < 0)
     {
         /* Read error. */
         perror ("read");
         exit (EXIT_FAILURE);
     }
     else 
        /*si ya no hay mas bytes*/
	if (nbytes == 0)
          /* End-of-file. */
           return -1;
        /*si hay mas bytes imprime lo leido*/
	else
        {
          /* Data read. */
          fprintf (stderr, "Server: got message: `%s'\n", buffer);
          return 0;
        }
}

