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; +}