#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#define TAILLE_BUF 128

int descServ;


void panic (const char *msg) {
  perror(msg);
  exit(1);
}
void fin (int sig) {
  int descServ;
  if (close (descServ) != -1)
    printf("Descripteur bien fermé\n");
  exit(0);
}

int main (int argc, char *argv[]) { 
  int descServ;
  int descClient;
  int len,max,max_old;
  int lg_addr_client = sizeof(struct sockaddr_in);
  int lgMsg = TAILLE_BUF;
  struct sockaddr_in addrServ;
  struct sockaddr_in addrClient;
  char *buf = (char*) malloc (TAILLE_BUF); 
  struct sigaction act;
  fd_set read_fd_set, test_fd_set; 

  descServ = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

  //Quitter proprement par ^C
  act.sa_handler = fin;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  sigaction(SIGINT, &act,0);

  //nommage du serv
  addrServ.sin_family = AF_INET;
  addrServ.sin_addr.s_addr = htonl(INADDR_ANY); //toutes les adresses possibles du serveur !
  addrServ.sin_port = htons(0); 
  
  if (bind (descServ,(struct sockaddr *) &addrServ,(sizeof(struct sockaddr_in))) == -1)
    panic("Erreur de nommage"); 
  
  if (getsockname (descServ,(struct sockaddr *) &addrServ,&len) == -1) 
    panic("Erreur lors de la recuperation du port");

  //Affichage des infos serveurs a communiquer aux clients
  printf("Infos sur le serveur:\n");
  printf("\tPort: %d\n",ntohs(addrServ.sin_port));

  //reception des messages des clients:
  listen (descServ,SOMAXCONN); //crée une liste d'attente
  FD_ZERO(&read_fd_set);
  FD_SET(descServ,&read_fd_set);
  max = descServ;

  for(;;) {
    int lus,desc;
    test_fd_set = read_fd_set;   
    printf("serveur en attente -> descMax : %d\n",max);
    if (select(max+1,&test_fd_set,(fd_set *) 0,(fd_set *) 0,(struct timeval*) 0) < 1)
      panic ("Pb Select");
    for (desc = 0;desc < max+1;desc++)
      if (FD_ISSET(desc,&test_fd_set)) {
	//message sur socket publique -> nv client ! 
	if (desc == descServ) {
	  descClient = accept (descServ,(struct sockaddr *) &addrClient,&lg_addr_client);
	  printf("  Nv client: %s : %d -> desc : %d\n",inet_ntoa(addrClient.sin_addr),ntohs(addrClient.sin_port),descClient);
	  FD_SET(descClient,&read_fd_set);
	  if (max < descClient)
	    max = descClient;
	}
	//sinon msg d'un ancien client
	else {
	  ioctl(desc,FIONREAD,&lus); //renvoie le nb de caractčres lisibles
	  if (lus == 0) {            //voir Rifflet page 219
	    printf("  Fermeture du client de desc %d\n",desc);
	    close(desc);
	    FD_CLR(desc,&read_fd_set);
	    // gerer la borne max de recherche des descripteurs
	    if (desc == max) {
	      max_old = max;
	      max = 0;
	      for (desc = 0; desc < max_old;desc++)
		if ((desc>max) && (FD_ISSET(desc,&read_fd_set))) 
		  max = desc;
	    }
	    //traitement d'un client courant !!!
	    else {
	      read(desc,buf,TAILLE_BUF);
	      printf("  Message %s recu du client de desc %d \n",buf,desc);
	    }
	  }
	}
      }
  }
}

/* Particulierement interessant quand les clients
sont longs a faire des requetes -> attente saisie
utilisateur par exemple
*/


syntax highlighted by Code2HTML, v. 0.9.1