From 236e2746569e699d97d7059c0ca462dc51df1a10 Mon Sep 17 00:00:00 2001 From: tonton Th Date: Sat, 28 Mar 2020 10:59:41 +0100 Subject: [PATCH] server is running, expect more bugs --- .gitignore | 5 + Makefile | 39 ++++- broadcast.c | 274 ++++++++++++++++++++++++++++++++ clients.c | 196 +++++++++++++++++++++++ commands.c | 446 ++++++++++++++++++++++++++++++++++++++++++++++++++++ drinks.c | 126 +++++++++++++++ lists.c | 187 ++++++++++++++++++++++ printlog.c | 54 +++++++ tools.c | 297 ++++++++++++++++++++++++++++++++++ xmem.c | 31 ++++ 10 files changed, 1653 insertions(+), 2 deletions(-) create mode 100644 broadcast.c create mode 100644 clients.c create mode 100644 commands.c create mode 100644 drinks.c create mode 100644 lists.c create mode 100644 printlog.c create mode 100644 tools.c create mode 100644 xmem.c diff --git a/.gitignore b/.gitignore index 5761abc..a568eaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ + + *.o + +guinnessd + diff --git a/Makefile b/Makefile index c5aa715..3a48752 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,46 @@ H_DEP = broadcast.h commands.h defines.h guinnessd.h printlog.h \ COPT = -Wall -g -# --------------------------------------------------------- +D_OBJS = xmem.o broadcast.o printlog.o lists.o tools.o drinks.o \ + commands.o clients.o -guinnessd.o: guinnessd.c Makefile +D_LIBS = -lpthread -lcrypt + +# --------------------------------------------------------- +# +# Main program +# + +guinnessd: guinnessd.o Makefile $(D_OBJS) + gcc -g $< $(D_OBJS) $(D_LIBS) -o $@ + +guinnessd.o: guinnessd.c Makefile $(H_DEP) gcc $(COPT) -c $< # --------------------------------------------------------- +# +# modules needed by the daemon +# +broadcast.o: broadcast.c Makefile $(H_DEP) + gcc $(COPT) -c $< +printlog.o: printlog.c Makefile $(H_DEP) + gcc $(COPT) -c $< +lists.o: lists.c Makefile $(H_DEP) + gcc $(COPT) -c $< +xmem.o: xmem.c Makefile $(H_DEP) + gcc $(COPT) -c $< +tools.o: tools.c Makefile $(H_DEP) + gcc $(COPT) -c $< +drinks.o: drinks.c Makefile $(H_DEP) + gcc $(COPT) -c $< +commands.o: commands.c Makefile $(H_DEP) + gcc $(COPT) -c $< +clients.o: clients.c Makefile $(H_DEP) + gcc $(COPT) -c $< + +# --------------------------------------------------------- + +clients.o: clients.c Makefile $(H_DEP) + gcc $(COPT) -c $< diff --git a/broadcast.c b/broadcast.c new file mode 100644 index 0000000..aa0f879 --- /dev/null +++ b/broadcast.c @@ -0,0 +1,274 @@ +/* + * guinnessd + * architecture clients/serveur guinness : broadcast messages + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "printlog.h" +#include "xmem.h" +#include "guinnessd.h" +#include "lists.h" +#include "tools.h" +#include "broadcast.h" +#include "drinks.h" + + +extern Elt *clients_list; +extern FILE *outerr; + + +static int count = 0; +static unsigned long id = 0; +static Elt *bdcast_list = NULL; + + +unsigned long get_first_id () { + unsigned long ret = id; + + if (bdcast_list) { + char *first_msg; + first_msg = elt_number (bdcast_list, 0); + ret = strtoul (first_msg, (char **)NULL, 10); + } + + return ret; +} + + +unsigned long get_last_id () { + unsigned long ret = id; + + if (bdcast_list) { + char *last_msg; + last_msg = elt_number (bdcast_list, get_nb_elts (bdcast_list) - 1); + ret = strtoul (last_msg, (char **)NULL, 10); + } + + return ret; +} + + +void next_broadcast (int new) { +#ifdef DEBUG + printlog (LOG_NOTIFY, "Suivant ? (%ld restants / %s)\n", + get_nb_elts (bdcast_list), new ? "NEW" : "SUITE"); +#endif + if ( (new && (get_nb_elts (bdcast_list) == 1) ) || + ( (!new) && (get_nb_elts (bdcast_list) >= 1) ) ) { + pthread_mutex_lock (&mutex_clients); + count = get_nb_elts (clients_list); + pthread_mutex_unlock (&mutex_clients); + id = get_last_id (); +#ifdef DEBUG + printlog (LOG_NOTIFY, "Message en lisse (id = %ld / count = %d)...\n", + id, count); +#endif + } +} + + +int broadcast (int t, const char *f, const char *m) { + int taille; + char sid[MAXSTRLEN]; + char stype[MAXSTRLEN]; + char *message; + + pthread_mutex_lock (&mutex_clients); + if (get_nb_elts (clients_list) == 0) { + pthread_mutex_unlock (&mutex_clients); + return TRUE; + } + pthread_mutex_unlock (&mutex_clients); + + pthread_mutex_lock (&mutex_broadcast); + + memset (sid, 0, MAXSTRLEN); + memset (stype, 0, MAXSTRLEN); + snprintf (sid, MAXSTRLEN - 1, "%ld", get_last_id () + 1); + snprintf (stype, MAXSTRLEN - 1, "%d", t); + + taille = (strlen (sid) + + strlen (stype) + + (f ? strlen (f) : 3) + + (m ? strlen (m) : 0) + + 5) * sizeof (char); + + message = xmalloc (taille); + memset (message, 0, taille); + /* i_| t_| f_| m_ */ + snprintf (message, taille, "%s%s%s%s%s%s%s", + sid, SEP, + stype, SEP, + f ? f : "---", SEP, + m ? m : ""); + + add_elt (&bdcast_list, message); + free (message); + next_broadcast (TRUE); + +#ifdef DEBUG + printlog (LOG_NOTIFY, + "Broadcast id = %s\t" + "type = %s\t" + "de = %s\n", + sid, + t == 1 ? "QUITTER" : + t == 2 ? "TOURNÉE" : + t == 3 ? "MESSAGE" : "RIEN", + f); +#endif + + pthread_mutex_unlock (&mutex_broadcast); + + return TRUE; +} + + +int new_message (long cid) { + int res; + + pthread_mutex_lock (&mutex_broadcast); + res = (id > cid); + pthread_mutex_unlock (&mutex_broadcast); + + return res; +} + + +int get_broadcastid () { + int res; + + pthread_mutex_lock (&mutex_broadcast); + res = id; + pthread_mutex_unlock (&mutex_broadcast); + + return res; +} + + +void get_broadcastmsg (int *t, char **f, char **m) { + char *token, *bdcast, *saveptr; + + pthread_mutex_lock (&mutex_broadcast); + bdcast = xstrdup (elt_number (bdcast_list, 0)); + pthread_mutex_unlock (&mutex_broadcast); + + if (bdcast) { +#ifdef DEBUG + printf ("Broadcast tokenisation : %s\n", bdcast); +#endif + + /* id */ + token = strtok_r (bdcast, SEP, &saveptr); +#ifdef DEBUG + printf ("Reçu : ID = %s\n", token); +#endif + + /* type */ + token = strtok_r (NULL, SEP, &saveptr); +#ifdef DEBUG + printf ("Reçu : TYPE = %s\n", token); +#endif + *t = atoi (token); + + /* from */ + token = strtok_r (NULL, SEP, &saveptr); +#ifdef DEBUG + printf ("Reçu : FROM = %s\n", token); +#endif + *f = NULL; + if (token) *f = xstrdup (token); + + /* message */ + token = strtok_r (NULL, SEP, &saveptr); +#ifdef DEBUG + printf ("Reçu : MESSAGE = %s\n", token); +#endif + *m = NULL; + if (token) *m = xstrdup (token); + + pthread_mutex_lock (&mutex_broadcast); + if (count > 0) count--; +#ifdef DEBUG + printf ("count = %d\n", count); +#endif + + if (count == 0) { + remove_elt_n (&bdcast_list, 0); +#ifdef DEBUG + printf ("Suppression du premier élément. Liste = %s\n", + bdcast_list ? "OK." : "NULL !"); +#endif + next_broadcast (FALSE); + } + pthread_mutex_unlock (&mutex_broadcast); + } +} + + +int send_broadcast (int socket_service, userinfos *infos) { + char datas[MAXSTRLEN]; + char head[MAXSTRLEN]; + char *from = NULL, *mesg = NULL, *breuv = NULL; + int type, cont = TRUE; + + memset (datas, 0, MAXSTRLEN); + get_broadcastmsg (&type, &from, &mesg); + + printlog (LOG_NOTIFY, "Broadcast pour [%s] : %s\n", + infos->nom, + type == 1 ? "QUITTER" : + type == 2 ? "TOURNÉE" : + type == 3 ? "MESSAGE" : + "ERREUR"); + printlog (LOG_NOTIFY, " de [%s] : %s\n", from, mesg ? mesg : "RIEN"); + + switch (type) { + case QUITTER: /* Un utilisateur se déconnecte */ + snprintf (datas, MAXSTRLEN - 1, "Déconnexion de [%s] : %s", + from, mesg); + break; + case TOURNEE: /* Tournée générale */ + if (mesg == NULL) { + snprintf (head, MAXSTRLEN - 1, + " -+- Tournée générale offerte par %s ! -+-", + from); + breuv = drinks_get (infos->prefb); + } else { + snprintf (head, MAXSTRLEN - 1, + " -+- Tournée de %s offerte par %s ! -+-", + mesg, from); + breuv = drinks_get (mesg); + } + snprintf (datas, MAXSTRLEN - 1, "%s\n%s%s\n", head, breuv, head); + free (breuv); + break; + case MESSAGE: /* Message */ + snprintf (datas, MAXSTRLEN - 1, "<%s> %s\n", from, mesg); + break; + default: + printlog (LOG_ERROR, "Type de message broadcast non supporté.\n"); + type = -1; + } + + if (from) free (from); + if (mesg) free (mesg); + + if (type != -1) cont = send_infos (socket_service, datas); + + return cont; +} diff --git a/clients.c b/clients.c new file mode 100644 index 0000000..de91282 --- /dev/null +++ b/clients.c @@ -0,0 +1,196 @@ +/* + * clients + * architecture clients/serveur guinness : clients list + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include +#include "defines.h" +#include "printlog.h" +#include "xmem.h" +#include "guinnessd.h" +#include "lists.h" +#include "tools.h" +#include "clients.h" + + +extern Elt *clients_list; + +void add_client (userinfos *infos) { + char *datas; + int size; + + size = strlen (infos->nom); + size += strlen (infos->prefb); + size += strlen (infos->cxdate); + size += strlen (infos->host); + size += strlen (infos->ip); + size += 5 * strlen (SEP) + 10; + + datas = xmalloc (size + 1); + + sprintf (datas, "%s%s%s%s%s%s%s%s%s%s%d", + infos->nom, SEP, + infos->prefb, SEP, + infos->cxdate, SEP, + infos->host, SEP, + infos->ip, SEP, + infos->port); + + add_elt (&clients_list, datas); + +#ifdef DEBUG + printf ("Taille des éléments :\n" + "nom : %d [%s]\n" + "bière : %d [%s]\n" + "date : %d [%s]\n" + "hôte : %d [%s]\n" + "ip : %d [%s]\n", + strlen (infos->nom), infos->nom, + strlen (infos->prefb), infos->prefb, + strlen (infos->cxdate), infos->cxdate, + strlen (infos->host), infos->host, + strlen (infos->ip), infos->ip); + + printf ("Ajout des infos : size = %d -- [%s]\n", size, datas); +#endif + + free (datas); +} + + +void remove_client (userinfos *infos) { + remove_elt (&clients_list, infos->nom); +} + + +int rename_client (userinfos *infos, const char *new_nick) { + if (exist_elt (clients_list, new_nick)) return FALSE; + remove_elt (&clients_list, infos->nom); + snprintf (infos->nom, MAXSTRLEN, "%s", new_nick); + add_client (infos); + return TRUE; +} + + +char *list_clients () { + char *list; + char *lstelt; + char *rt; + char text[MAXSTRLEN + 1]; + int size; + int i; + + size = strlen ("Client(s) connecté(s) :\n"); + for (i = 0 ; i < get_nb_elts (clients_list) ; i++) { + lstelt = elt_number (clients_list, i); + rt = strstr (lstelt, SEP); + strncpy (text, lstelt, rt - lstelt); + text[rt - lstelt] = 0; + size += 1 + strlen (text); + } + + list = xmalloc ((size + 1) * sizeof (char)); + + strcpy (list, "Client(s) connecté(s) :\n"); + for (i = 0 ; i < get_nb_elts (clients_list) ; i++) { + lstelt = elt_number (clients_list, i); + rt = strstr (lstelt, SEP); + strncpy (text, lstelt, rt - lstelt); + text[rt - lstelt] = 0; + strcat (list, text); + strcat (list, "\n"); + } + + return list; +} + +char *infos_client (int admin, const char *nick) { + char *datas; + char *infos; + char *token, *use, *saveptr; + char *nom = NULL, *biere = NULL, *date = NULL; + char *host = NULL, *ip = NULL, *port = NULL; + int size = 0; + + infos = get_elt (clients_list, nick); + if (! infos) { + datas = xmalloc (strlen (nick) + strlen (" : pseudo inconnu !\n")); + sprintf (datas, "%s : pseudo inconnu !\n", nick); + return datas; + } + + use = xstrdup (infos); + + /* nom */ + token = strtok_r (use, SEP, &saveptr); + if (token) nom = xstrdup (token); + + /* bière */ + token = strtok_r (NULL, SEP, &saveptr); + if (token) biere = xstrdup (token); + + /* date */ + token = strtok_r (NULL, SEP, &saveptr); + if (token) date = xstrdup (token); + + /* hôte */ + token = strtok_r (NULL, SEP, &saveptr); + if (token) host = xstrdup (token); + + /* ip */ + token = strtok_r (NULL, SEP, &saveptr); + if (token) ip = xstrdup (token); + + /* port */ + token = strtok_r (NULL, SEP, &saveptr); + if (token) port = xstrdup (token); + + size += strlen ("Pseudo : "); + size += strlen ("Bière : "); + size += strlen ("Connexion : "); + size += 1 + (nom ? strlen (nom) : 1); + size += 1 + (biere ? strlen (biere) : 1); + size += 1 + (date ? strlen (date) : 1); + if (admin) { + size += strlen ("Hôte : "); + size += strlen ("IP : "); + size += strlen ("Port : "); + size += 1 + (host ? strlen (host) : 1); + size += 1 + (ip ? strlen (ip) : 1); + size += 1 + (port ? strlen (port) : 1); + } + + datas = xmalloc (size + 1); + + sprintf (datas, + "Pseudo : %s\n" + "Bière : %s\n" + "Connexion : %s\n", + nom ? nom : "-", + biere ? biere : "-", + date ? date : "-"); + if (admin) + sprintf (datas, "%s" + "Hôte : %s\n" + "IP : %s\n" + "Port : %s\n", + datas, + host ? host : "-", + ip ? ip : "-", + port ? port : "-"); + + if (nom) free (nom); + if (biere) free (biere); + if (date) free (date); + if (host) free (host); + if (ip) free (ip); + if (port) free (port); + + return datas; +} diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..9f4d677 --- /dev/null +++ b/commands.c @@ -0,0 +1,446 @@ +/* + * commands + * architecture clients/serveur guinness + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.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" + + +extern FILE *logfile; +extern int online; +extern char *admin_passwd; +extern char *chemin; +extern Elt *clients_list; +extern Elt *drinks_list; + + +/* Signification des champs de commandes: + * NOM AIDE ARGS ADM INTRV FCT + */ +cmdslst cmds_srv[] = { + {"help", "cette page d'aide", FALSE, FALSE, FALSE, f_help}, + {"quit", "quitter", FALSE, FALSE, FALSE, f_quit}, + {"list", "liste des clients connectés", FALSE, FALSE, FALSE, f_list}, + {"blist", "liste des boissons disponibles", FALSE, FALSE, FALSE, f_bevr}, + {"round", "tournée générale (boisson en option ou préférée)", + TRUE, FALSE, FALSE, f_turn}, + {"cold", "la guinness est servie à - de 10°C, sinon entre 12 et 15", + FALSE, FALSE, FALSE, f_cold}, + {"msg", "message à tous les clients", TRUE, FALSE, FALSE, f_mesg}, + {"infos", "renvoie les infos du serveur", TRUE, FALSE, FALSE, f_info}, + {"nick", "change de pseudo", TRUE, FALSE, FALSE, f_nick}, + {"123456789", "nombre de verres à recevoir (boisson en option ou " + "préférée)", FALSE, FALSE, TRUE, f_glas}, + {"admin", "passer en mode administration", TRUE, FALSE, FALSE, f_sadm}, + {"33", "arrêter le serveur", FALSE, TRUE, FALSE, f_shut}, + {"add", "ajoute un utilisateur dans la liste des habitués", + TRUE, TRUE, FALSE, f_addu}, + {"del", "enlève un utilisateur de la liste des habitués", + TRUE, TRUE, FALSE, f_delu}, + {"rldb", "recharge la liste des boissons", FALSE, TRUE, FALSE, f_rldb}, + {"save", "sauve la liste des habitués", FALSE, TRUE, FALSE, f_save}, + {"load", "charge la liste des habitués", FALSE, TRUE, FALSE, f_load}, + {NULL, NULL, FALSE, FALSE, FALSE, NULL} +}; + + + +int security_ok (cmdslst cmd, userinfos infos) { + return ( (cmd.adm == FALSE) || + ( (cmd.adm == TRUE) && (infos.admin == TRUE) ) ); +} + + +int reply (int socket_service, char *commande, userinfos *infos) { + int i, cont = TRUE, found = FALSE; + + + /* Tout d'abord, on remplace \n par \0 ! */ + for (i = 0 ; i <= strlen (commande) ; i++) + if ( (commande[i] == '\n') || (commande[i] == '\r') ) { + commande[i] = 0; + } + + if (strncmp (commande, "admin ", 6) != 0) + printlog (LOG_NOTIFY, "Commande de %s : [%s] (%d)\n", + infos->nom, + commande, + strlen (commande) ); + else { +#ifdef DEBUG + printlog (LOG_NOTIFY, "Commande de %s : [%s]\n", infos->nom, commande); +#else + printlog (LOG_NOTIFY, "Commande de %s : admin XXXXXX\n", infos->nom); +#endif + } + + fflush (logfile); + + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) { + int cmp = -1; + cmdslst cmd = cmds_srv[i]; + + if ( (cmd.interv) && + ( (strlen (commande) == 1) || + (commande[1] == ' ') ) ) { + cmp = strchr (cmd.nom, commande[0]) == NULL ? -1 : 0; + } else { + if (cmd.args) + cmp = strncmp (commande, cmd.nom, strlen (cmd.nom) ); + else + cmp = strcmp (commande, cmd.nom); + } + + if ( (cmp == 0) && (security_ok (cmd, *infos) == TRUE ) ) { + found = TRUE; + printlog (LOG_NOTIFY, "Commande reconnue : %s\n", cmd.nom); + cont = cmd.fct (socket_service, commande, infos); + break; + } + } + + if (! found) + send_infos (socket_service, "Don't flood me with stupidities !\n"); + + return cont; +} + + +int send_servercmds (int socket_service) { + char *data; + char cmd[MAXSTRLEN]; + int size = 0; + int i; + + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) { + memset (cmd, 0, MAXSTRLEN); + if (cmds_srv[i].adm) + snprintf (cmd, MAXSTRLEN - 1, "*%s\n", cmds_srv[i].nom); + else if (cmds_srv[i].interv) + snprintf (cmd, MAXSTRLEN - 1, "+%s\n", cmds_srv[i].nom); + else + snprintf (cmd, MAXSTRLEN - 1, "%s\n", cmds_srv[i].nom); + size += strlen (cmd); + } + + data = xmalloc ((size + 1) * sizeof (char)); + strcpy (data, ""); + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) { + memset (cmd, 0, MAXSTRLEN); + if (cmds_srv[i].adm) + snprintf (cmd, MAXSTRLEN - 1, "*%s\n", cmds_srv[i].nom); + else if (cmds_srv[i].interv) + snprintf (cmd, MAXSTRLEN - 1, "+%s\n", cmds_srv[i].nom); + else + snprintf (cmd, MAXSTRLEN - 1, "%s\n", cmds_srv[i].nom); + strcat (data, cmd); + } + + return send_infos (socket_service, data); +} + + +int f_help (int socket_service, const char *commande, userinfos *infos) { + char *data; + char ligne[MAXSTRLEN]; + int size = 0; + int i; + + memset (ligne, 0, MAXSTRLEN); + size = strlen ("Commandes (précédées du caractère de commande) :\n"); + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) { + if (security_ok (cmds_srv[i], *infos) == TRUE) { + if (cmds_srv[i].args) + snprintf (ligne, MAXSTRLEN - 1, " %s [opts]\t: %s\n", + cmds_srv[i].nom, cmds_srv[i].aide); + else + snprintf (ligne, MAXSTRLEN - 1, " %s%s: %s\n", + cmds_srv[i].nom, + strlen (cmds_srv[i].nom) < 5 ? "\t\t" : "\t", + cmds_srv[i].aide); + size += strlen (ligne); + } + } + + data = xmalloc ((size + 1) * sizeof (char)); + + strcpy (data, "Commandes (précédées du caractère de commande) :\n"); + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) { + if (security_ok (cmds_srv[i], *infos) == TRUE) { + if (cmds_srv[i].args) + snprintf (ligne, MAXSTRLEN - 1, " %s [opts]\t: %s\n", + cmds_srv[i].nom, cmds_srv[i].aide); + else + snprintf (ligne, MAXSTRLEN - 1, " %s%s: %s\n", + cmds_srv[i].nom, + strlen (cmds_srv[i].nom) < 5 ? "\t\t" : "\t", + cmds_srv[i].aide); + strcat (data, ligne); + } + } + + return send_infos (socket_service, data); +} + + +int f_quit (int socket_service, const char *commande, userinfos *infos) { + return FALSE; +} + + +int f_list (int socket_service, const char *commande, userinfos *infos) { + char *data; + int cont; + + pthread_mutex_lock (&mutex_clients); + data = list_clients (); + pthread_mutex_unlock (&mutex_clients); + + cont = send_infos (socket_service, data); + free (data); + + return cont; +} + + +int f_bevr (int socket_service, const char *commande, userinfos *infos) { + char *data; + int size = 0; + int i; + int cont; + + size = strlen ("Boissons disponibles :\n"); + for (i = 0 ; i < get_nb_elts (drinks_list) ; i++) { + size += strlen (elt_number (drinks_list, i) ); + size += strlen ("\n"); + } + + data = xmalloc ((size + 1) * sizeof (char)); + + strcpy (data, "Boissons disponibles :\n"); + for (i = 0 ; i < get_nb_elts (drinks_list) ; i++) { + strcat (data, elt_number (drinks_list, i) ); + strcat (data, "\n"); + } + + cont = send_infos (socket_service, data); + free (data); + + return cont; +} + + +int f_cold (int socket_service, const char *commande, userinfos *infos) { + int cont; + + if (infos->cold == TRUE) { + infos->cold = FALSE; + cont = send_infos (socket_service, "Température normale.\n"); + } else { + infos->cold = TRUE; + cont = send_infos (socket_service, "Température fraîche (10°C).\n"); + } + + return cont; +} + + +int f_turn (int socket_service, const char *commande, userinfos *infos) { + int cont = TRUE; + char *breuv = NULL; + + if (strlen (commande) > 5) breuv = xstrdup (commande+6); + + printlog (LOG_NOTIFY, "Breuvage pour tournée : %s\n", + breuv ? breuv : "préféré"); + + if ( ( (breuv != NULL) && (exist_elt (drinks_list, breuv) == TRUE) ) || + (breuv == NULL) ) { + if (! broadcast (TOURNEE, infos->nom, breuv) ) + cont = send_infos (socket_service, "Erreur de transmission !\n"); + } else + cont = send_infos (socket_service, "Boisson non disponible !\n"); + + free (breuv); + + return cont; +} + + + +int f_mesg (int socket_service, const char *commande, userinfos *infos) { + int cont = TRUE; + + if (! broadcast (MESSAGE, infos->nom, commande + 4) ) + cont = send_infos (socket_service, "Erreur de transmission !\n"); + + return cont; +} + + +int f_info (int socket_service, const char *commande, userinfos *infos) { + int cont = TRUE; + char *data; + + if (strlen (commande) == 5) { + data = xmalloc (MAXSTRLEN + 1); + snprintf (data, MAXSTRLEN, "guinnessd - v %s (compilation %s : %s)\n", + VERSION, OS_TYPE, COMPIL_DATE); + } else + data = infos_client (infos->admin, commande + 6); + + cont = send_infos (socket_service, data); + + free (data); + + return cont; +} + + +int f_nick (int socket_service, const char *commande, userinfos *infos) { + int cont = TRUE, rename_ok; + char *new_nick, *old_nick; + + old_nick = xstrdup (infos->nom); + new_nick = xstrdup (commande + 5); + + pthread_mutex_lock (&mutex_clients); + rename_ok = rename_client (infos, new_nick); + pthread_mutex_unlock (&mutex_clients); + + if (rename_ok) { + char texte[MAXSTRLEN + 1]; + snprintf (texte, MAXSTRLEN, "%s s'appelle maintenant %s.\n", + old_nick, new_nick); + if (! broadcast (MESSAGE, NULL, texte) ) + cont = send_infos (socket_service, "Erreur de transmission !\n"); + } else { + cont = send_infos (socket_service, "Pseudo déjà utilisé !\n"); + } + + free (old_nick); + free (new_nick); + + return cont; +} + + +int f_glas (int socket_service, const char *commande, userinfos *infos) { + int i, nb, cont = TRUE; + char *breuv; + char *data; + + if (strlen (commande) > 2) + breuv = xstrdup (commande + 2); + else + breuv = xstrdup (infos->prefb); + + printlog (LOG_NOTIFY, "Breuvage désiré : %s\n", breuv); + + data = drinks_get (breuv); + nb = atoi (commande); + for (i = 0 ; i < nb ; i++) + if ( (cont = send_infos (socket_service, data) ) == FALSE) break; + free (data); + free (breuv); + + return cont; +} + + +int f_sadm (int socket_service, const char *commande, userinfos *infos) { + int cont = TRUE; + + if ( (admin_passwd) && (strcmp (admin_passwd, commande + 6) == 0) ) { + char message[] = "Vous êtes maintenant ADMINISTRATEUR.\n" + "Nouvelles commandes :"; + char *data; + int size = 0, i; + + infos->admin = TRUE; + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) + if (cmds_srv[i].adm) size += 1 + strlen (cmds_srv[i].nom); + + size += strlen (message); + data = xmalloc ((size + 1) * sizeof (char)); + memset (data, 0, size); + + strcpy (data, message); + for (i = 0 ; cmds_srv[i].nom != NULL ; i++) + if (cmds_srv[i].adm) { + strcat (data, " "); + strcat (data, cmds_srv[i].nom); + } + + cont = send_infos (socket_service, data); + free (data); + } else { + infos->admin = FALSE; + cont = send_infos (socket_service, + "Vous n'êtes PLUS administrateur.\n"); + } + + return cont; +} + + +int f_shut (int socket_service, const char *commande, userinfos *infos) { + + online = FALSE; + send_infos (socket_service, "Arrêt en cours...\n"); + + return FALSE; +} + + +int f_rldb (int socket_service, const char *commande, userinfos *infos) { + + free_list (&drinks_list); + add_elt (&drinks_list, "guinness"); + if (! chemin) chemin = xstrdup (DRINKS_DIR); + drinks_list_files (chemin); + drinks_display_list (); + + return send_infos (socket_service, "Liste des boissons rechargée...\n"); +} + + +int f_addu (int socket_service, const char *commande, userinfos *infos) { + return send_infos (socket_service, "Fonction non implémentée...\n"); +} + +int f_delu (int socket_service, const char *commande, userinfos *infos) { + return send_infos (socket_service, "Fonction non implémentée...\n"); +} + +int f_save (int socket_service, const char *commande, userinfos *infos) { + return send_infos (socket_service, "Fonction non implémentée...\n"); +} + +int f_load (int socket_service, const char *commande, userinfos *infos) { + return send_infos (socket_service, "Fonction non implémentée...\n"); +} diff --git a/drinks.c b/drinks.c new file mode 100644 index 0000000..f8eaff6 --- /dev/null +++ b/drinks.c @@ -0,0 +1,126 @@ +/* + * drinks + * architecture clients/serveur guinness + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "xmem.h" +#include "printlog.h" +#include "lists.h" +#include "drinks.h" +#include "pint.h" + +extern char *pinte; +extern char *chemin; +extern Elt *drinks_list; +extern FILE *logfile; +extern FILE *outerr; + + +char *drinks_get_from_file (const char *nom) { + struct stat fileinfos; + char filename[MAXSTRLEN + 1]; + char *datas; + FILE *fichier; + + snprintf (filename, MAXSTRLEN, "%s/%s", chemin, nom); + if (stat (filename, &fileinfos) == -1) { + printlog (LOG_ERROR, "Accès impossible au fichier [%s]\n", + filename); + perror ("stat "); + return NULL; + } + + if ( (fichier = fopen (filename, "r")) == NULL) return NULL; + datas = xmalloc ((fileinfos.st_size + 3) * sizeof (char)); + memset (datas, 0, fileinfos.st_size + 3); + fread (datas, sizeof (char), fileinfos.st_size, fichier); + fclose (fichier); + + return datas; +} + + +char *drinks_get (const char *nom) { + char *breuvage = NULL; + int i; + + if (nom == NULL) return NULL; + + /* Élément 0 (Guinness) disponible par défaut */ + if (strcmp (nom, "guinness") == 0) breuvage = xstrdup (pinte); + + /* Sinon on cherche dans la liste des fichiers : + * on commence à 1 pour éviter la pinte de Guinness qui est traitée + * juste avant. + */ + if (! breuvage) { + for (i = 1 ; i < get_nb_elts (drinks_list) ; i++) + if (strcmp (nom, elt_number (drinks_list, i)) == 0) + breuvage = drinks_get_from_file (nom); + } + + /* Dernier cas : on n'a rien trouvé => pinte par défaut */ + if (! breuvage) breuvage = xstrdup (pinte); + + return breuvage; +} + +void drinks_list_files (const char *path) { + DIR *rep; + struct dirent *dirinfos; + struct stat fileinfos; + int nbfiles = 0; + char filename[MAXSTRLEN + 1]; + + if ( (rep = opendir (path)) == NULL) { + printlog (LOG_ERROR, "Impossible d'ouvrir le répertoire [%s]\n", path); +#ifdef DEBUG + perror ("opendir "); +#endif + return; + } + + printlog (LOG_NOTIFY, "Liste des fichiers à intégrer :\n"); + while ((dirinfos = readdir (rep)) != NULL) { + snprintf (filename, MAXSTRLEN, "%s/%s", path, dirinfos->d_name); + if (stat (filename, &fileinfos) == -1) { + printlog (LOG_ERROR, "Accès impossible au fichier [%s]\n", + filename); +#ifdef DEBUG + perror ("stat "); +#endif + } + if ( (dirinfos->d_name[0] != '.') && + ( (fileinfos.st_mode & S_IFMT) == S_IFREG) ) { + printlog (LOG_NOTIFY, " fichier : [%s]\n", + dirinfos->d_name); + add_elt (&drinks_list, dirinfos->d_name); + nbfiles++; + } + } + printlog (LOG_NOTIFY, "Fin de la liste : %d fichier%s.\n", + nbfiles, nbfiles > 1 ? "s" : ""); + closedir (rep); +} + + +void drinks_display_list () { + int i; + char *breuvage; + + printlog (LOG_NOTIFY, "Boissons disponibles :\n"); + for (i = 0 ; i < get_nb_elts (drinks_list) ; i++) { + breuvage = elt_number (drinks_list, i); + printlog (LOG_NOTIFY, "%d\t: %s\n", i, breuvage); + } +} diff --git a/lists.c b/lists.c new file mode 100644 index 0000000..26c5375 --- /dev/null +++ b/lists.c @@ -0,0 +1,187 @@ +/* + * lists + * architecture clients/serveur guinness + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include "defines.h" +#include "xmem.h" +#include "lists.h" + + +void add_elt (Elt **elt, const char *nom) { + Elt *e; + + if (*elt == NULL) { + *elt = xmalloc ((1) * sizeof (Elt)); + (*elt)->nom = xstrdup (nom); + (*elt)->next = NULL; + } else { + e = *elt; + while (e->next != NULL) e = e->next; + e->next = xmalloc ((1) * sizeof (Elt)); + e = e->next; + e->nom = xstrdup (nom); + e->next = NULL; + } +} + + +void remove_elt (Elt **elt, const char *nom) { + Elt *e = *elt, *p = NULL; + int res = FALSE; + char *rt, *text ; + + do { + if (e != NULL) { + if ((rt = strstr (e->nom, SEP)) != NULL) { + text = xmalloc (rt - e->nom + 2); + memset (text, 0, rt - e->nom + 2); + strncpy (text, e->nom, rt - e->nom); +#ifdef DEBUG + printf ("Comparaison (l) de [%s] avec [%s]\n", text, nom); +#endif + res = (strcmp (text, nom) == 0); + free (text); + } else { +#ifdef DEBUG + printf ("Comparaison (c) de [%s] avec [%s]\n", e->nom, nom); +#endif + res = (strcmp (e->nom, nom) == 0); + } + if (res == FALSE) { + p = e; + e = e->next; + } + } + } while ( (e != NULL) && (res != TRUE) ); + + if (e == NULL) return; + if (e == *elt) *elt = e->next; + if (p) p->next = e->next; + free (e->nom); + free (e); +} + + +void remove_elt_n (Elt **elt, int i) { + Elt *e = *elt, *p = NULL; + int n = 0; + + while ( (e != NULL) && (n != i) ) { + n++; + e = e->next; + } + if (e == NULL) return; + if (e == *elt) *elt = e->next; + if (p) p->next = e->next; + free (e->nom); + free (e); +} + + +int get_nb_elts (Elt *elt) { + Elt *e = elt; + int n = 0; + + while (e != NULL) { + n++; + e = e->next; + } + + return n; +} + + +char *elt_number (Elt *elt, int i) { + Elt *e = elt; + int n = 0; + + while ( (e != NULL) && (n != i) ) { + n++; + e = e->next; + } + if (e == NULL) return NULL; + + return e->nom; +} + + +int exist_elt (Elt *elt, const char *nom) { + Elt *e = elt; + int res = FALSE; + char *rt, *text ; + + do { + if (e != NULL) { + if ((rt = strstr (e->nom, SEP)) != NULL) { + text = xmalloc (rt - e->nom + 2); + memset (text, 0, rt - e->nom + 2); + strncpy (text, e->nom, rt - e->nom); +#ifdef DEBUG + printf ("Comparaison (l) de [%s] avec [%s]\n", text, nom); +#endif + res = (strcmp (text, nom) == 0); + free (text); + } else { +#ifdef DEBUG + printf ("Comparaison (c) de [%s] avec [%s]\n", e->nom, nom); +#endif + res = (strcmp (e->nom, nom) == 0); + } + e = e->next; + } + } while ( (e != NULL) && (res != TRUE) ); + + return res; +} + + +char *get_elt (Elt *elt, const char *nom) { + Elt *e = elt; + int res = FALSE; + char *rt, *text ; + + do { + if (e != NULL) { + if ((rt = strstr (e->nom, SEP)) != NULL) { + text = xmalloc (rt - e->nom + 2); + memset (text, 0, rt - e->nom + 2); + strncpy (text, e->nom, rt - e->nom); +#ifdef DEBUG + printf ("Comparaison (l) de [%s] avec [%s]\n", text, nom); +#endif + res = (strcmp (text, nom) == 0); + free (text); + } else { +#ifdef DEBUG + printf ("Comparaison (c) de [%s] avec [%s]\n", e->nom, nom); +#endif + res = (strcmp (e->nom, nom) == 0); + } + if (res == FALSE) e = e->next; + } + } while ( (e != NULL) && (res != TRUE) ); + + if (e == NULL) return NULL; + + return e->nom; +} + + +void free_list (Elt **elt) { + Elt *e = *elt, *p; + + while (e != NULL) { + p = e; + e = e->next; + free (p->nom); + free (p); + } + *elt = NULL; +} diff --git a/printlog.c b/printlog.c new file mode 100644 index 0000000..bb6127e --- /dev/null +++ b/printlog.c @@ -0,0 +1,54 @@ +/* + * printlog + * architecture clients/serveur guinness + * Thomas Nemeth / Arnaud Giersch -- le 23 août 2001 + * + */ + +#include +#include +#ifdef SunOS +#include +#else +#include +#endif +#include +#include "defines.h" +#include "printlog.h" + + +extern FILE *outerr; +extern FILE *logfile; + + +void printlog (log_level loglevel, const char *format, ...) { + va_list ap; + FILE *stream = logfile; + time_t now; + struct tm *today; + char date_time[MAXSTRLEN]; + + va_start (ap, format); + + switch (loglevel) { + case LOG_NOTIFY: + stream = logfile; + break; + case LOG_ERROR: + stream = outerr; + break; + default: + stream = outerr; + break; + } + + time (&now); + today = localtime (&now); + memset (date_time, 0, MAXSTRLEN); + strftime (date_time, MAXSTRLEN - 1, "%a %d %b %Y %T", today); + fprintf (stream, "guinnessd: %s - ", date_time); + vfprintf (stream, format, ap); + + va_end (ap); +} + diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..dc41a71 --- /dev/null +++ b/tools.c @@ -0,0 +1,297 @@ +/* + * tools + * Création et manipulation de sockets + * Thomas Nemeth -- le 15 juin 2001 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "xmem.h" +#include "tools.h" + +/* + * Ouverture d'une socket de type flot de données + * + * création d'une socket serveur : port != 0 + * + */ +int ouvre_socket (int port, char *adr_ip, struct sockaddr_in *ptr_adresse) { + int desc_soc; + int lg_adresse = sizeof (struct sockaddr_in); + int lg_linger = sizeof (struct linger); + struct sockaddr_in adresse; + struct linger ling; + + /* + * Création de la socket + * + */ + if ( (desc_soc = socket (AF_INET, SOCK_STREAM, 0) ) == -1) { +#ifdef DEBUG + fprintf (stderr, "Ne peut pas ouvrir la socket de connexion.\n"); +#endif + perror (__FILE__ " socket"); + return -1; + } + + /* + * Affectation des options + * + */ + if (port != 0) { + int opt = 1; + if (setsockopt (desc_soc, SOL_SOCKET, + SO_REUSEADDR, &opt, sizeof (int) ) == -1) { +#ifdef DEBUG + fprintf (stderr, "Impossible de positionner REUSEADDR.\n"); +#endif + perror (__FILE__ " setsockopt -- REUSEADDR"); + return -1; + } + } + ling.l_onoff = 0; + ling.l_linger = 0; + if (setsockopt (desc_soc, SOL_SOCKET, SO_LINGER, &ling, lg_linger) == -1) { +#ifdef DEBUG + fprintf (stderr, "Impossible de positionner LINGER.\n"); +#endif + perror (__FILE__ " setsockopt -- LINGER"); + return -1; + } + + /* + * Préparation de l'adresse d'attachement + * + */ + memset (&adresse, 0, sizeof (adresse) ); + adresse.sin_family = AF_INET; + if (adr_ip) { + struct in_addr ia; + + if (inet_aton(adr_ip, &ia)) { + adresse.sin_addr = ia; + } else { + struct hostent *h; + + h = gethostbyname(adr_ip); + if (!h) { + fprintf (stderr, "Adresse %s inconnue.\n", adr_ip); + return -1; + } + memcpy (&adresse.sin_addr.s_addr, h->h_addr, h->h_length); + } + } else + adresse.sin_addr.s_addr = htonl (INADDR_ANY); + adresse.sin_port = htons (port); + + /* + * Demande d'attachement de la socket + * + */ + if (bind (desc_soc, (struct sockaddr*) &adresse, lg_adresse) == -1) { +#ifdef DEBUG + fprintf (stderr, + "Ne peut donner de nom à la socket de connexion.\n" + "Attendez quelques minutes avant de relancer.\n"); +#endif + perror (__FILE__ " bind"); + close (desc_soc); + return -1; + } + + /* + * Récupération de l'adresse effective d'attachement + * + */ + if (ptr_adresse != NULL) + getsockname (desc_soc, (struct sockaddr *) ptr_adresse, &lg_adresse); + + return desc_soc; +} + + +int connect_server (const char *machine, int port) { + struct hostent *serveur; + struct sockaddr_in adresse_serveur, adresse_client; + int socket_client; + + /* Recherche de la machine où se trouve le serveur */ + if ( (serveur = gethostbyname (machine) ) == NULL) { +#ifdef DEBUG + fprintf (stderr, "Machine %s inconnue...\n", machine); +#endif + return -1; + } + + /* Création et attachement de la socket du client -- + * port quelconque => 0 + */ + if ( (socket_client = ouvre_socket + (0, NULL, (struct sockaddr_in *) &adresse_client)) == -1) { +#ifdef DEBUG + fprintf (stderr, "Création de la socket du client impossible.\n"); +#endif + return -1; + } + + /* Préparation de l'adresse du serveur */ + adresse_serveur.sin_family = AF_INET; + adresse_serveur.sin_port = htons (port); + memcpy (&adresse_serveur.sin_addr.s_addr, + serveur->h_addr, serveur->h_length); + + /* Demande de connexion au serveur */ + if (connect (socket_client, (struct sockaddr *) &adresse_serveur, + sizeof (adresse_serveur) ) == -1) { +#ifdef DEBUG + fprintf (stderr, "Impossible de se connecter au serveur.\n"); +#endif + perror (__FILE__ " connect"); + return -1; + } + + return socket_client; +} + + +int install_server (int port, char *adr_ip, struct sockaddr_in *ecoute) { + int socket_ecoute; + + /* Ouverture de la socket */ + if ( (socket_ecoute = ouvre_socket (port, adr_ip, ecoute)) == -1) { +#ifdef DEBUG + fprintf (stderr, "Création de la socket du serveur impossible.\n"); +#endif + return -1; + } + + /* Déclaration d'ouverture du service */ + if (listen (socket_ecoute, 10) == -1) { +#ifdef DEBUG + fprintf (stderr, "Impossible d'enregistrer le service.\n"); +#endif + perror (__FILE__ " listen"); + return -1; + } + + return socket_ecoute; +} + + +/* + * Fonction de réception de données + * + */ +int read_infos (int socket_data, char *infos) { + int nb; + + /* SSIZE_MAX = 2147483647 */ + memset (infos, 0, MAXSTRLEN); + nb = read (socket_data, infos, MAXSTRLEN - 1); + + if ( (nb == -1) || (nb == 0) ) { +#ifdef DEBUG + fprintf (stderr, "Erreur de connexion réception !\n"); +#endif + if ( (errno == EPIPE) || (nb == 0) ) return FALSE; /* cont = FALSE; */ + } + +#ifdef DEBUG + printf ("Reçu : [%s] lg = %d/%d\n", infos, strlen (infos), nb); +#endif + + return TRUE; +} + + +/* + * Fonction d'émisson de données + * + */ +int send_infos (int socket_data, const char *infos) { + +#ifdef DEBUG + printf ("Émission de : %s [%d]\n", infos, strlen (infos)); +#endif + + if (write (socket_data, (void *) infos, strlen (infos) + 1) == -1) { + /* Erreur : plus de socket ! */ +#ifdef DEBUG + fprintf (stderr, "Erreur de connexion émission !\n"); +#endif + if (errno == EPIPE) return FALSE; /*cont = FALSE;*/ + } +#ifdef DEBUG + fprintf (stderr, "Émission ok !\n"); +#endif + return TRUE; +} + + +void get_sock_infos (int sock, char **nom, char **adr, int *prl, int *prd) { + struct sockaddr_in name; +#ifdef OpenBSD + int namelen; +#else + socklen_t namelen; +#endif + struct hostent *machine; + + /* Initialisations en cas d'échecs */ + *nom = NULL; + *adr = NULL; + *prd = 0; + + /* Infos locales (port) */ + namelen = sizeof (name); + if (getsockname (sock, (struct sockaddr *) &name, &namelen) == 0) + *prl = ntohs (name.sin_port); + else { + perror ("getsockname() "); + *prl = 0; + } + + /* Port et adresse IP distants */ + namelen = sizeof (name); + if (getpeername (sock, (struct sockaddr *) &name, &namelen) != 0) { +#ifdef DEBUG + perror ("Erreur de récupération d'information sur pair !\n" + "getpeername() "); +#else + perror ("Impossible d'obtenir les infos distantes "); +#endif + return; + } + + *adr = xstrdup (inet_ntoa (name.sin_addr)); + *prd = ntohs (name.sin_port); + + /* Nom de machine distante */ + machine = gethostbyaddr ((char *)&name.sin_addr, + sizeof name.sin_addr, name.sin_family); + if (machine == NULL) { +#ifdef DEBUG + perror ("Erreur de récupération de nom de pair.\n" + "gethostbyaddr() "); + fprintf (stderr, "Adresse : %s (%s)\tFamille : %d (2 == AF_INET)\n", + *adr, (char *)&name.sin_addr, name.sin_family); +#else + perror ("Impossible d'obtenir le nom d'hôte distant "); +#endif + return; + } + + *nom = xstrdup (machine->h_name); +} diff --git a/xmem.c b/xmem.c new file mode 100644 index 0000000..2608860 --- /dev/null +++ b/xmem.c @@ -0,0 +1,31 @@ +/* + * xmem + * architecture clients/serveur guinness : gestion mémoire + * Thomas Nemeth -- le 24 août 2001 + * + */ + +#include +#include +#include +#include +#include "xmem.h" + + +void *xmalloc (size_t taille) { + void *ret = malloc (taille); + if (ret == NULL) { + perror ("malloc() "); + exit (-1); + } else + return ret; +} + +char *xstrdup (const char *chaine) { + char *ret = strdup (chaine); + if (ret == NULL) { + perror ("strdup() "); + exit (-1); + } else + return ret; +}