#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>
#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;
  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;
  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);

  //Ignorer la mort des fils
  signal(SIGCHLD,SIG_IGN);

  //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,5); //crée une liste d'attente
                 //SOMAXCONN est la valeur max du systeme
  for(;;) {   
    printf("serveur en attente d'un message\n");
    descClient = accept (descServ,(struct sockaddr *) &addrClient,&lg_addr_client);
    if (descClient == -1)
      panic("Connection ratée");
    switch (fork()) {
    case -1:
      panic ("Duplication ratée");
    case 0:
      read(descClient,buf,TAILLE_BUF);
      //simule un long traitement de données
      sleep(2);
      printf("Message %s recu de %s sur port %d \n",buf,inet_ntoa(addrClient.sin_addr),ntohs(addrClient.sin_port));
      write(descClient,"Requete bien traitée",20);
      close(descClient);
      exit(0);
    default:
      close(descClient);      
    }
  }
}

/*
Rendu possible car il ya recopie de l'espace d'adressage 
et aussi de la table des descripteurs ouverts lors d'un fork()
Attention ne marcherait pas avec une thread -> car l'acceptation
d'un nouveau client ecraserait le descripteur client (partagé)

Résultat:

$ serveur
serveur en attente d'un message
  -> Attente 2 secondes
Message Bonjour1 recu de 127.0.0.1 sur port 1058
serveur en attente d'un message
  -> Attente 2 secondes
Message Bonjour2 recu de 127.0.0.1 sur port 1059
serveur en attente d'un message
  -> Attente 2 secondes
Message Bonjour3 recu de 127.0.0.1 sur port 1060

$ serveur-fork
serveur en attente d'un message
serveur en attente d'un message
serveur en attente d'un message
serveur en attente d'un message
  -> Attente 2 secondes
Message Bonjour1 recu de 127.0.0.1 sur port 1062
Message Bonjour2 recu de 127.0.0.1 sur port 1063
Message Bonjour3 recu de 127.0.0.1 sur port 1064
*/


syntax highlighted by Code2HTML, v. 0.9.1