589 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			589 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * guinnessd
 | |
|  * architecture clients/serveur guinness
 | |
|  * Thomas Nemeth -- le 15 juin 2001
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <time.h>
 | |
| #include <errno.h>
 | |
| #include <signal.h>
 | |
| #include <pthread.h>
 | |
| #include <fcntl.h>
 | |
| #include <getopt.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/socket.h>
 | |
| #include <netinet/in.h>
 | |
| #include <string.h>
 | |
| #include <strings.h>
 | |
| #include <locale.h>
 | |
| #include "defines.h"
 | |
| #include "xmem.h"
 | |
| #include "tools.h"
 | |
| #include "printlog.h"
 | |
| #include "lists.h"
 | |
| #include "broadcast.h"
 | |
| #include "drinks.h"
 | |
| #include "clients.h"
 | |
| #include "guinnessd.h"
 | |
| #include "commands.h"
 | |
| #include "config.h"
 | |
| 
 | |
| pthread_mutex_t mutex_clients;
 | |
| 
 | |
| /* Config specifique  serveur */
 | |
| char *adr_ip       = NULL;
 | |
| int   port         = 0;
 | |
| int   online       = TRUE;
 | |
| char *fichierlog   = NULL;
 | |
| char *fichiercfg   = NULL;
 | |
| char *chemin       = NULL;
 | |
| char *admin_passwd = NULL;
 | |
| FILE *logfile      = NULL;
 | |
| FILE *outerr       = NULL;
 | |
| Elt  *clients_list = NULL;
 | |
| Elt  *drinks_list  = NULL;
 | |
| 
 | |
| /* Config specifique connexion des clients */
 | |
| char *pseudo       = NULL;
 | |
| char *drink        = NULL;
 | |
| char *logout       = NULL;
 | |
| 
 | |
| 
 | |
| #ifdef SunOS
 | |
| char *crypt(const char *key, const char *salt);
 | |
| #else
 | |
| extern char *crypt __P ((__const char *__key, __const char *__salt));
 | |
| #endif
 | |
| 
 | |
| 
 | |
| void install_handler ();
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Gestionnaire de signal SIGPIPE, SIGTERM, SIGQUIT et SIGINT
 | |
|  *
 | |
|  */
 | |
| void handler_signaux (int sig) {
 | |
|     switch (sig) {
 | |
|         case SIGPIPE:
 | |
|             printlog (LOG_NOTIFY, "Signal SIGPIPE recu...\n");
 | |
|             install_handler ();
 | |
|             break;
 | |
|         case SIGTERM:
 | |
|         case SIGQUIT:
 | |
|         case SIGINT:
 | |
|             online = FALSE;
 | |
|             printlog (LOG_NOTIFY, "Signal de terminaison recu...\n");
 | |
|             break;
 | |
|         default:
 | |
|             printlog (LOG_NOTIFY, "Signal recu...\n");
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Lecture du fichier de config : recuperation des valeurs
 | |
|  *
 | |
|  */
 | |
| char *get_string_from_token (char *line) {
 | |
|     char *result = line;
 | |
|     char *tmp;
 | |
|     int   keyval = 0;
 | |
| 
 | |
|     while ( (keyval != 1) && (result [0] != 0) ) {
 | |
|         if (result [0] == '=') keyval = 1;
 | |
|         if (keyval == 0) result++;
 | |
|     }
 | |
|     tmp = result++;
 | |
|     while (tmp [0] != 0) {
 | |
|         if (tmp [0] == '\n') tmp [0] = 0;
 | |
|         tmp++;
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Lecture du fichier de config
 | |
|  *
 | |
|  */
 | |
| void load_config () {
 | |
|     FILE *file;
 | |
|     char  tmpstr[MAXSTRLEN + 1];
 | |
|     char *value;
 | |
| 
 | |
|     /* Ouverture du fichier */
 | |
|     if ( (file = fopen (fichiercfg?fichiercfg:CONFIG_FILE, "r") ) != NULL) {
 | |
|         /* Lecture du fichier */
 | |
|         while (! feof (file) ) {
 | |
|             memset (tmpstr, 0, MAXSTRLEN + 1);
 | |
|             fgets (tmpstr, (int) MAXSTRLEN, file);
 | |
|             value = get_string_from_token (tmpstr);
 | |
|             if ( (strncmp (tmpstr, "port=", 5) == 0) && (port == 0) )
 | |
|                 port = atoi (value);
 | |
|             if ( (strncmp (tmpstr, "passwd=", 7) == 0) &&
 | |
|                  (admin_passwd == NULL) )
 | |
|                 admin_passwd = xstrdup (crypt (value, "Gs") + 2);
 | |
|             if ( (strncmp (tmpstr, "rep=", 4) == 0) && (chemin == NULL) )
 | |
|                 chemin = xstrdup (value);
 | |
|             if ( (strncmp (tmpstr, "pseudo=", 7) == 0) && (pseudo == NULL) )
 | |
|                 pseudo = xstrdup (value);
 | |
|             if ( (strncmp (tmpstr, "drink=", 6) == 0) && (drink == NULL) )
 | |
|                 drink = xstrdup (value);
 | |
|             if ( (strncmp (tmpstr, "logout=", 7) == 0) && (logout == NULL) )
 | |
|                 logout = xstrdup (value);
 | |
|         }
 | |
|         fclose (file);
 | |
| #ifdef DEBUG
 | |
|     } else {
 | |
|         fprintf (stderr, "Pas de fichier de config (%s).\n", CONFIG_FILE);
 | |
| #endif
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Aide
 | |
|  *
 | |
|  */
 | |
| void Usage (int help) {
 | |
|     printf ("guinnessd by Thomas Nemeth - v %s (compilation %s : %s)\n",
 | |
|             VERSION, OS_TYPE, COMPIL_DATE);
 | |
|     if (help)
 | |
|         printf ("Usage : guinnessd [-h] [-v] [-b] [-p port] "
 | |
|                 "[-s passwd] [-d chemin] [-l fichier] [-f fichier]\n"
 | |
|                 "   -h         : aide sur les parametres\n"
 | |
|                 "   -v         : affiche la version\n"
 | |
|                 "   -b         : detache le serveur du terminal\n"
 | |
|                 "   -a adresse : specifie l'adresse du serveur\n"
 | |
|                 "   -p port    : specifie le numero du port\n"
 | |
|                 "   -s passwd  : specifie le mot de passe d'aministration\n"
 | |
|                 "   -d chemin  : indique le chemin ou se"
 | |
|                 " trouvent les ascii-arts\n"
 | |
|                 "   -l fichier : fichier de log\n"
 | |
|                 "   -f fichier : fichier de configuration\n\n");
 | |
|     exit (1);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Traitement des arguments
 | |
|  *
 | |
|  */
 | |
| int traite_argv (int argc, char *argv[]) {
 | |
|     int option;
 | |
|     int detach = FALSE;
 | |
| 
 | |
|     /* Verification des parametres */
 | |
|     while ((option = getopt (argc, argv, "hvba:p:s:d:l:f:")) != -1) {
 | |
|         switch (option) {
 | |
|             case 'h' :
 | |
|                 Usage (TRUE);
 | |
|                 break;
 | |
|             case 'v' :
 | |
|                 Usage (FALSE);
 | |
|                 break;
 | |
|             case 'b' :
 | |
|                 detach = TRUE;
 | |
|                 break;
 | |
|             case 'a' :
 | |
|                 adr_ip = optarg;
 | |
|                 break;
 | |
|             case 'p' :
 | |
|                 port = atoi (optarg);
 | |
|                 break;
 | |
|             case 's' :
 | |
|                 admin_passwd = xstrdup (crypt (optarg, "Gs") + 2);
 | |
|                 break;
 | |
|             case 'd' :
 | |
|                 if (! chemin) {
 | |
|                     if (optarg[0] == '/') {
 | |
|                         chemin = xstrdup (optarg);
 | |
|                     } else {
 | |
|                         char *Pwd;
 | |
|                         Pwd = xmalloc ((MAXSTRLEN + 1) * sizeof (char));
 | |
|                         getcwd (Pwd, MAXSTRLEN);
 | |
|                         chemin = xmalloc ( (strlen (Pwd) + strlen (optarg) + 2)
 | |
|                                            * sizeof (char) );
 | |
|                         snprintf (chemin, MAXSTRLEN, "%s/%s",
 | |
|                                   Pwd, optarg);
 | |
|                     }
 | |
|                 }
 | |
|                 break;
 | |
|             case 'l' :
 | |
|                 if (! fichierlog) {
 | |
|                     fichierlog = xstrdup (optarg);
 | |
|                 }
 | |
|                 break;
 | |
|             case 'f' :
 | |
|                 if (! fichiercfg) {
 | |
|                     fichiercfg = xstrdup (optarg);
 | |
|                 }
 | |
|                 break;
 | |
|             default:
 | |
|                 Usage (TRUE);
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
|     if (optind < argc) {
 | |
|         if (argc - optind == 1)
 | |
|             fprintf (stderr, "%s: option inconnue --", argv[0]);
 | |
|         else
 | |
|             fprintf (stderr, "%s: options inconnues --", argv[0]);
 | |
|         for ( ; optind < argc ; optind++)
 | |
|             fprintf (stderr, " %s", argv[optind]);
 | |
|         fprintf (stderr, "\n");
 | |
|         Usage (TRUE);
 | |
|     }
 | |
| 
 | |
|     return detach;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Fonction initiant la connexion.
 | |
|  *
 | |
|  */
 | |
| int initiate (int socket_service, userinfos *infos) {
 | |
|     int        cont = TRUE;
 | |
|     char       userdatas[MAXSTRLEN];
 | |
|     char      *datas, *token, *saveptr;
 | |
|     char       delim[] = "\n\r";
 | |
|     char      *nom_distant = NULL;
 | |
|     char      *ip_distant = NULL;
 | |
|     int        port_distant = 0;
 | |
|     int        port_local = 0;
 | |
|     time_t     now;
 | |
|     struct tm *today;
 | |
| 
 | |
|     memset (userdatas, 0, MAXSTRLEN);
 | |
| 
 | |
|     /* Recuperation des infos sur le connecte */
 | |
|     get_sock_infos (socket_service,
 | |
|                     &nom_distant, &ip_distant,
 | |
|                     &port_local, &port_distant);
 | |
|     if (ip_distant) {
 | |
|         snprintf (infos->ip, MAXSTRLEN, "%s", ip_distant);
 | |
|         free (ip_distant);
 | |
|     } else sprintf (infos->ip, "0.0.0.0");
 | |
|     if (nom_distant) {
 | |
|         snprintf (infos->host, MAXSTRLEN, "%s", nom_distant);
 | |
|         free (nom_distant);
 | |
|     } else sprintf (infos->host, "none");
 | |
|     infos->port = port_distant;
 | |
| 
 | |
|     printlog (LOG_NOTIFY, "Connexion entrante : %s %s\n",
 | |
|               infos->ip, infos->host ? infos->host : "");
 | |
|     printlog (LOG_NOTIFY, "Ports (loc/dist)   : %d / %d\n",
 | |
|               port_local, infos->port);
 | |
| 
 | |
|     /* PROTOCOLE DE CONNEXION */
 | |
|     /* 1. envoi des commandes du serveur */
 | |
|     if ( (cont = send_servercmds (socket_service)) == FALSE)
 | |
|         return cont;
 | |
| 
 | |
|     /* 2. attente des donnees du connecte */
 | |
|     if ( (cont = read_infos (socket_service, userdatas)) == FALSE)
 | |
|         return cont;
 | |
| 
 | |
|     /* FIN DU PROTOCOLE : Vericifations / ajout dans la liste / affichage */
 | |
|     datas = xstrdup (userdatas);
 | |
| 
 | |
|     /* Nom d'utilisateur */
 | |
|     token = strtok_r (datas, delim, &saveptr);
 | |
|     snprintf (infos->nom, MAXSTRLEN, "%s", token ? token : pseudo);
 | |
| 
 | |
|     /* Boisson preferee */
 | |
|     token = strtok_r (NULL, delim, &saveptr);
 | |
|     snprintf (infos->prefb, MAXSTRLEN, "%s", token ? token : drink);
 | |
| 
 | |
|     /* Message d'au-revoir */
 | |
|     token = strtok_r (NULL, delim, &saveptr);
 | |
|     snprintf (infos->logout, MAXSTRLEN, "%s", token ? token : logout);
 | |
| 
 | |
|     /* Date de connexion */
 | |
|     time (&now);
 | |
|     today = localtime (&now);
 | |
|     strftime (infos->cxdate, MAXSTRLEN, "%a %d %b %Y %T", today);
 | |
| 
 | |
|     printlog (LOG_NOTIFY, "Utilisateur        : [%s]\n", infos->nom);
 | |
|     printlog (LOG_NOTIFY, "Boisson preferee   : [%s]\n", infos->prefb);
 | |
|     printlog (LOG_NOTIFY, "Message de logout  : [%s]\n", infos->logout);
 | |
|     printlog (LOG_NOTIFY, "Date de connexion  : [%s]\n", infos->cxdate);
 | |
| 
 | |
|     pthread_mutex_lock (&mutex_clients);
 | |
|     if (exist_elt (clients_list, infos->nom)) {
 | |
|         char nick_ok[MAXSTRLEN+1];
 | |
|         snprintf (nick_ok, MAXSTRLEN, "@%s", infos->nom);
 | |
|         snprintf (infos->nom, MAXSTRLEN, "%s", nick_ok);
 | |
|         send_infos (socket_service, "@Pseudo deja utilise !\n");
 | |
|         printlog (LOG_NOTIFY, "Pseudo deje utilise => %s\n", infos->nom);
 | |
|         pthread_mutex_unlock (&mutex_clients);
 | |
|         return FALSE;
 | |
|     }
 | |
|     send_infos (socket_service, "Bienvenue sur le serveur de Guinness.\n");
 | |
|     add_client (infos);
 | |
|     pthread_mutex_unlock (&mutex_clients);
 | |
| 
 | |
|     if (! exist_elt (drinks_list, infos->prefb))
 | |
|         send_infos (socket_service,
 | |
|                     "Votre boisson preferee n'est pas disponible sur ce"
 | |
|                     " serveur !\nVous aurez des Guinness a la place.\n");
 | |
| 
 | |
|     /* Passage en mode non bloquant */
 | |
|     fcntl (socket_service, F_SETFL, O_NONBLOCK);
 | |
| 
 | |
|     return cont;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Fonction de traitement de la connexion avec les clients
 | |
|  *
 | |
|  */
 | |
| void thread_service (int *sock_serv) {
 | |
|     pthread_t tid            = pthread_self ();
 | |
|     long      old_id         = get_broadcastid ();
 | |
|     int       socket_service = (int) *sock_serv;
 | |
|     int       cont           = TRUE;
 | |
|     int       nb;
 | |
|     userinfos infos;
 | |
|     char      commande[MAXSTRLEN + 1];
 | |
| 
 | |
|     pthread_detach (tid);
 | |
| 
 | |
|     memset (infos.nom,    0, MAXSTRLEN + 1);
 | |
|     memset (infos.prefb,  0, MAXSTRLEN + 1);
 | |
|     memset (infos.logout, 0, MAXSTRLEN + 1);
 | |
|     infos.admin = FALSE;
 | |
|     infos.cold  = FALSE;
 | |
| 
 | |
|     cont = initiate (socket_service, &infos);
 | |
| 
 | |
|     if (cont) {
 | |
|         snprintf (commande, MAXSTRLEN,
 | |
|                   "%s a rejoint le serveur de Guinness.\n", infos.nom);
 | |
|         broadcast (MESSAGE, NULL, commande);
 | |
|     }
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     printlog (LOG_NOTIFY, "Pret a recevoir des commandes.\n");
 | |
| #endif
 | |
| 
 | |
|     while (cont == TRUE) {
 | |
|         memset (commande, 0, MAXSTRLEN + 1);
 | |
| 
 | |
|         /* Lecture des caracteres recus */
 | |
|         do {
 | |
|             sleep (1);
 | |
|             nb = read (socket_service, commande, MAXSTRLEN);
 | |
|             if ( (nb == -1) || (nb == 0) ) {
 | |
|                 if ( (errno == EAGAIN) && (nb == -1) ) continue;
 | |
|                 if ( (errno == EPIPE) || (nb == 0) ) {
 | |
|                     cont = FALSE;
 | |
|                 } else {
 | |
|                     printlog (LOG_ERROR, "Erreur de connexion reception !\n");
 | |
|                 }
 | |
|             }
 | |
|         } while ( (cont != FALSE) &&
 | |
|                   (nb < 0) &&
 | |
|                   (new_message (old_id) != TRUE) );
 | |
| 
 | |
| #ifdef DEBUG
 | |
|         printlog (LOG_NOTIFY, "Commande recue.\n");
 | |
| #endif
 | |
|         if (cont == TRUE) {
 | |
|             /* Traitement de la commande */
 | |
|             if (nb > 0)
 | |
|                 cont = reply (socket_service, commande, &infos);
 | |
|             /* Broadcast */
 | |
|             if (new_message (old_id) == TRUE) {
 | |
|                 old_id = get_broadcastid ();
 | |
|                 cont = send_broadcast (socket_service, &infos);
 | |
| #ifdef DEBUG
 | |
|                 printlog (LOG_ERROR, "Emission broadcast pour %s (id = %ld)\n",
 | |
|                          infos.nom, old_id);
 | |
| #endif
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     printlog (LOG_NOTIFY, "Bye bye %s...\n", infos.nom);
 | |
| 
 | |
|     if (infos.nom[0] != '@') {
 | |
|         pthread_mutex_lock (&mutex_clients);
 | |
|         remove_client (&infos);
 | |
|         pthread_mutex_unlock (&mutex_clients);
 | |
| 
 | |
|         broadcast (QUITTER, infos.nom, infos.logout);
 | |
|     }
 | |
| 
 | |
|     close (socket_service);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Installation du gestionnaire de signal SIGPIPE et autres...
 | |
|  *
 | |
|  */
 | |
| void install_handler () {
 | |
|     signal (SIGPIPE, handler_signaux);
 | |
|     signal (SIGTERM, handler_signaux);
 | |
|     signal (SIGQUIT, handler_signaux);
 | |
|     signal (SIGINT,  handler_signaux);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Initialisation generale
 | |
|  *
 | |
|  */
 | |
| void guinnessd_init (int argc, char *argv[]) {
 | |
|     pthread_mutexattr_t mutex_attr;
 | |
|     char	*cptr;
 | |
| 
 | |
|     setlocale (LC_ALL, "");
 | |
|     install_handler ();
 | |
| 
 | |
|     /* Valeurs par defaut */
 | |
|     logfile = stdout;
 | |
|     outerr  = stderr;
 | |
| 
 | |
| /* est-ce bien la place pour initialiser des trucs avant le parsing de
 | |
|    la ligne de commande ? Eg: la variable d'environnement DRINKS_DIR
 | |
|  */
 | |
| 
 | |
| if (NULL!=(cptr=getenv("DRINKS_DIR"))) {
 | |
| 	chemin = xstrdup(cptr);
 | |
| 	}
 | |
| 
 | |
| 
 | |
|     /* Traitement des parametres */
 | |
|     if (traite_argv (argc, argv) == TRUE) {
 | |
|         switch (fork()) {
 | |
|             case -1: /* erreur */
 | |
|                 perror ("fork()"); 
 | |
|                 exit (-1);
 | |
|             case  0: /* le fils */
 | |
|                 setsid ();
 | |
|                 break;
 | |
|             default: /* le pere */
 | |
|                 exit (0);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Lecture du fichier de configuration */
 | |
|     load_config ();
 | |
| 
 | |
|     /* Initialisation des semaphores */
 | |
|     pthread_mutexattr_init (&mutex_attr);
 | |
|     pthread_mutex_init (&mutex_broadcast, &mutex_attr);
 | |
|     pthread_mutex_init (&mutex_clients, &mutex_attr);
 | |
| 
 | |
|     /* Affectation des parametres */
 | |
|     if (IS_NOT_GOOD (pseudo))  SET_STRING (pseudo,  DEFAULT_PSEUDO);
 | |
|     if (IS_NOT_GOOD (drink))   SET_STRING (drink,   DEFAULT_DRINK);
 | |
|     if (IS_NOT_GOOD (logout))  SET_STRING (logout,  DEFAULT_LOGOUT);
 | |
|     if (port == 0) port = DEFAULT_SERVER_PORT;
 | |
|     if (fichierlog) {
 | |
|         if ((logfile = fopen (fichierlog, "a"))) {
 | |
|             outerr  = logfile;
 | |
|         } else {
 | |
|             fprintf (stderr, "Impossible d'ouvrir le fichier %s : %s\n",
 | |
|                      fichierlog, strerror(errno));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Option pour le buffer de logs */
 | |
|     setvbuf (logfile, NULL, _IOLBF, 0);
 | |
| 
 | |
|     /* Creation de la liste de boissons par defaut*/
 | |
|     add_elt (&drinks_list, "guinness");
 | |
| 
 | |
|     if (! chemin) chemin = xstrdup (DRINKS_DIR);
 | |
|     drinks_list_files (chemin);
 | |
|     drinks_display_list ();
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Fonction principale
 | |
|  *
 | |
|  */
 | |
| int main (int argc, char *argv[]) {
 | |
|     int                  socket_ecoute;
 | |
|     int                  socket_service;
 | |
|     socklen_t            lg_adresse = sizeof (struct sockaddr_in);
 | |
|     struct sockaddr_in   adresse;
 | |
|     pthread_t            pthread_id;
 | |
| 
 | |
|     guinnessd_init (argc, argv);
 | |
| 
 | |
|     /* Installation de l'ecoute du serveur */
 | |
|     if ( (socket_ecoute = install_server (port, adr_ip, NULL)) == -1) {
 | |
|         printlog (LOG_ERROR, "Impossible d'installer le service.\n");
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     /* Passage en mode non-bloquant */
 | |
|     fcntl (socket_ecoute, F_SETFL, O_NONBLOCK);
 | |
| 
 | |
|     /* Boucle d'attente et d'ouverture de connexions */
 | |
|     printlog (LOG_NOTIFY, "Serveur en attente de connexions (port %d)...\n",
 | |
|               port);
 | |
|     while (online == TRUE) {
 | |
|         sleep (1);
 | |
| 
 | |
|         /* Attente d'une connexion */
 | |
|         socket_service = accept (socket_ecoute, (struct sockaddr *) &adresse,
 | |
|                                  &lg_adresse);
 | |
| 
 | |
|         /* SIGPIPE */
 | |
|         if ( (socket_service == -1) && (errno == EINTR) ) continue;
 | |
| 
 | |
|         /* PAS DE CONNEXION => mode non bloquant pour attendre un ordre de
 | |
|          * terminaison
 | |
|          */
 | |
|         if ( (socket_service == -1) && (errno == EAGAIN) ) continue;
 | |
| 
 | |
|         /* Autre erreur socket */
 | |
|         if (socket_service == -1) {
 | |
|             /* Erreur */
 | |
|             printlog (LOG_ERROR,
 | |
|                       "Erreur d'acceptation de socket, errno = %d.\n",
 | |
|                       errno);
 | |
|             perror (__FILE__ " accept");
 | |
|             close (socket_ecoute);
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         /* Ici connexion acceptee */
 | |
|         printlog (LOG_NOTIFY, "Connexion acceptee...\n");
 | |
| 
 | |
|         /* Lancement d'une activite de traitement */
 | |
|         if (pthread_create (&pthread_id, NULL/*pthread_attr_default*/,
 | |
|                             (void *) thread_service,
 | |
|                             (void *) &socket_service) == -1) {
 | |
|             printlog (LOG_ERROR, "Erreur creation thread de service.\n");
 | |
|             close (socket_service);
 | |
|         }
 | |
|         /* fflush (logfile); */
 | |
|         sleep (2);
 | |
|     }
 | |
| 
 | |
|     printlog (LOG_NOTIFY, "Arret du serveur demande.\n");
 | |
|     /* fflush (logfile); */
 | |
|     close (socket_ecoute);
 | |
| 
 | |
|     free_list (&clients_list);
 | |
|     free_list (&drinks_list);
 | |
| 
 | |
|     pthread_mutex_destroy (&mutex_broadcast);
 | |
|     pthread_mutex_destroy (&mutex_clients);
 | |
| 
 | |
|     return 0;
 | |
| }
 | 
