/* serv_2_reuseAddr.c */

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

#define PORT_NUMBER 60000
#define REQUETES 3    /* Nb  max de requetes en attente */
#define TAMPON 100

/* sortie avec un message d'erreur contextualisé */
void erreur(char *msg) {
  perror(msg);
  exit(1);
}

int main(int argc, char *argv[]) {
  int sock_serveur, sock_client, port_number=PORT_NUMBER, len;
  const int one = 1;
  char *env_port;
  struct sockaddr_in sockaddr_serveur, sockaddr_client;
  unsigned int taille_client = sizeof(sockaddr_client);
  char buffer[TAMPON];
  char *ack="Bonjour !\n";
  char *eot="Au revoir !\n";

  /* gestion du numéro du port */
  env_port = getenv("GHDL_TCPPORT");
  if (env_port != NULL) {
    port_number = atol(env_port);
    if ((port_number < 1024) || (port_number > 65535))
      erreur("Mauvais numéro de port");
  }
  printf("Utilisation du port %d\n", port_number);

  /* Création d'une socket TCP */
  if ((sock_serveur = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    erreur("Echec lors de la création de la socket");

  /* Fabrication de la structure sockaddr_in du serveur */
  memset(&sockaddr_serveur, 0, sizeof(sockaddr_serveur));
  sockaddr_serveur.sin_family = AF_INET;
  sockaddr_serveur.sin_addr.s_addr = htonl(INADDR_ANY);
  sockaddr_serveur.sin_port = htons(port_number);

#ifdef SO_REUSEADDR
  if (setsockopt(sock_serveur, SOL_SOCKET,
            SO_REUSEADDR, &one, sizeof(one)) < 0)
    erreur("setsockopt(SO_REUSEADDR)");
#endif
#ifdef SO_REUSEPORT
  if (setsockopt(sock_serveur, SOL_SOCKET,
             SO_REUSEPORT, &one, sizeof(one)) < 0)
    erreur("setsockopt(SO_REUSEPORT)");
#endif

  /* Branche la socket */
  if (bind(sock_serveur, (struct sockaddr *) &sockaddr_serveur,
                              sizeof(sockaddr_serveur)) < 0)
    erreur("Echec de bind() du serveur");

  /* Ecoute la socket */
  if (listen(sock_serveur, REQUETES) < 0)
    erreur("Echec de listen() du serveur");

  /* Boucle infinie */
  while (1) {

    /* Attend une connexion */
    if ((sock_client = accept(sock_serveur,
       (struct sockaddr *) &sockaddr_client, &taille_client)) < 0)
      erreur("accept() : Echec d'attente de connexion");
    fprintf(stdout, "Client connecté de %s\n",
                           inet_ntoa(sockaddr_client.sin_addr));

    /* Petit message de bienvenue */  
    len = strlen(ack);
    if (send(sock_client, ack, len, 0) != len)
      erreur("Echec d'envoi du message de bienvenue");

    /* attend quelque chose */
    if (recv(sock_client, buffer, TAMPON, 0) < 0)
      erreur("Echec de réception du message du client");

    /* Adieu, serveur cruel ! */  
    len = strlen(eot);
    if (send(sock_client, eot, len, 0) != len)
      erreur("Echec d'envoi du message d'adieu");

    close(sock_client);
  }
}
