Compare commits

..

15 Commits

Author SHA1 Message Date
mco-system
6b89f86b71 doc: fix bad encoding 2025-10-05 18:36:17 +11:00
65b4622447 Merge pull request 'docker' (#2) from docker into master
Reviewed-on: #2
2025-10-05 11:26:03 +11:00
fb0ea65c80 Merge branch 'master' into docker 2025-10-05 11:25:06 +11:00
mco-system
c313b58375 fix+doc: fix missing CMD directive in dockerfile + updated doc 2025-10-05 11:23:45 +11:00
mco-system
002154f58f fix: missing CMD in Dockerfile 2025-10-05 11:07:10 +11:00
6159b7d07e Merge pull request 'docker' (#1) from docker into master
Reviewed-on: #1
2025-10-05 10:52:27 +11:00
mco-system
58c7549e65 fix: use extern mutex and COPT -fPIE -Wno-error. Add Dockerfile 2025-10-05 10:50:44 +11:00
mco-system
25ccec2fd3 WIP: missing picoles dir 2025-10-05 10:32:35 +11:00
tonton Th
8a9dff3514 faciltate access to the drink's storage 2020-04-20 23:30:44 +02:00
tonton Th
311baad6cb asciification du code source 2020-04-14 23:41:07 +02:00
tonton Th
efeef4140b première tournée !!! 2020-03-28 15:27:55 +01:00
tonton Th
0ef949ce91 client compiled :) 2020-03-28 11:56:49 +01:00
tonton Th
236e274656 server is running, expect more bugs 2020-03-28 10:59:41 +01:00
tonton Th
0040d27acc added pint.h needed by drinks.c 2020-03-28 10:53:42 +01:00
tonton Th
5e17585bea mostly useless fixes 2020-03-28 10:19:13 +01:00
27 changed files with 2553 additions and 56 deletions

6
.gitignore vendored
View File

@@ -1 +1,7 @@
*.o *.o
guinnessd
guinness

20
Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM debian:12 AS guinnessd-base
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y make gcc && \
useradd -m -d /home/guinness -s /bin/false -r guinness
FROM guinnessd-base
COPY . /home/guinness/src
WORKDIR /home/guinness
RUN make -C /home/guinness/src && \
mv /home/guinness/src/guinnessd /usr/local/bin && \
mv /home/guinness/src/picoles /usr/local/share && \
chmod +x /usr/local/bin/guinnessd && \
rm -Rf /home/guinness/src && \
apt-get remove -y make gcc && \
apt-get autoremove -y
USER guinness
CMD ["/usr/local/bin/guinnessd", "-p", "1664", "-d", "/usr/local/share/picoles"]

View File

@@ -4,14 +4,61 @@
# Makefile handcrafted by tTh # Makefile handcrafted by tTh
# #
H_DEP = broadcast.h commands.h defines.h guinnessd.h printlog.h \ all: guinness guinnessd
xmem.h clients.h config.h drinks.h lists.h tools.h
COPT = -Wall -g
# --------------------------------------------------------- # ---------------------------------------------------------
guinnessd.o: guinnessd.c Makefile H_DEP = broadcast.h commands.h defines.h guinnessd.h printlog.h \
xmem.h clients.h config.h drinks.h lists.h tools.h
COPT = -fPIE -Wno-error -g
D_OBJS = xmem.o broadcast.o printlog.o lists.o tools.o drinks.o \
commands.o clients.o
C_OBJS = xmem.o tools.o
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 $<
#
guinness: guinness.o Makefile $(D_OBJS)
gcc -g $< $(C_OBJS) $(D_LIBS) -o $@
guinness.o: guinness.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 $< gcc $(COPT) -c $<
# --------------------------------------------------------- # ---------------------------------------------------------

4
Makefile.docker Normal file
View File

@@ -0,0 +1,4 @@
.PHONY: build
build:
docker build -t guinnessd:latest .

125
README.md
View File

@@ -12,18 +12,139 @@ retraite sanitaire, de sortir la disqueuse et de tenter de trouver
le bug. Et ça ne va pas être simple, le Makefile d'origine est le bug. Et ça ne va pas être simple, le Makefile d'origine est
**très** convolué... **très** convolué...
Par la suite, j'ai l'intention d'y apporter quelques modifications
que je trouverais à mon gout. Elles seront décrites plus bas
dans la page.
## Méthodologie : ## Méthodologie :
Pour commencer, je vais utiliser un mélange de [rache](https://la-rache.com/) Pour commencer, je vais utiliser un mélange de [rache](https://la-rache.com/)
et de [poudre verte](https://poudreverte.org/), additionné d'un peu de et de [poudre verte](https://poudreverte.org/), additionné d'un peu de
jus de citron pour le goût... jus de citron pour le goût : importer les fichiers un à un jusqu'à ce
que ça marche. Et par la suite, remttre les choses au clair.
Première étape : tenter de compiler le `main()` du serveur. Oké, il demande Première étape : tenter de compiler le `main()` du serveur. Oké, il demande
un certain nombre de `.h`, que je m'empresse de lui fournir à partir de un certain nombre de `.h`, que je m'empresse de lui fournir à partir de
l'original. C'est au moment où il me demande le `config.h` que j'allume l'original. C'est au moment où il me demande le `config.h` que j'allume
la disqueuse, je n'ai qu'un `config.h.in` sous la main. la disqueuse, je n'ai qu'un `config.h.in` sous la main. Qu'à cela ne tienne,
_kraftons_ vite ce fichier manquant à la main.
Voilà finalement, avec cette méthode (que je n'hésite à appeler le
goutte-à-goutte), j'ai reconstitué un Makefile qui fonctionne et
compile le client et le serveur.
## Résultat : ## Résultat :
Et voilà une session typique de remote-picole :
```
tth@lubitel:~/Devel/GuinnessServer$ ./guinnessd
guinnessd: Sat 28 Mar 2020 15:21:35 - Impossible d'ouvrir le repertoire [/var/tmp/drinks.d]
guinnessd: Sat 28 Mar 2020 15:21:35 - Boissons disponibles :
guinnessd: Sat 28 Mar 2020 15:21:35 - 0 : guinness
guinnessd: Sat 28 Mar 2020 15:21:35 - Serveur en attente de connexions (port 1664)...
guinnessd: Sat 28 Mar 2020 15:22:18 - Connexion acceptee...
guinnessd: Sat 28 Mar 2020 15:22:18 - Connexion entrante : 127.0.0.1 localhost
guinnessd: Sat 28 Mar 2020 15:22:18 - Ports (loc/dist) : 1664 / 47647
guinnessd: Sat 28 Mar 2020 15:22:18 - Utilisateur : [tth]
guinnessd: Sat 28 Mar 2020 15:22:18 - Boisson preferee : [guinness]
guinnessd: Sat 28 Mar 2020 15:22:18 - Message de logout : [Bye bye...]
guinnessd: Sat 28 Mar 2020 15:22:18 - Date de connexion : [Sat 28 Mar 2020 15:22:18]
guinnessd: Sat 28 Mar 2020 15:22:19 - Broadcast pour [tth] : MESSAGE
guinnessd: Sat 28 Mar 2020 15:22:19 - de [---] : tth a rejoint le serveur de Guinness.
```
« Ah, c'est l'heure d'aller boire une bière, et comme il ne faut jamais « Ah, c'est l'heure d'aller boire une bière, et comme il ne faut jamais
boire le ventre vide, je vais manger une Guinness avant. » boire le ventre vide, je vais manger une Guinness avant. »
```
tth@lubitel:~/Devel/GuinnessServer$ ./guinness -u tth
Serveur : [127.0.0.1] Port : [1664]
Utilisateur : [tth] Boisson : [guinness] Logout : [Bye bye...]
Préfixe : [/]
-+- Connexion acceptee. -+-
Bienvenue sur le serveur de Guinness.
> <---> tth a rejoint le serveur de Guinness.
> /1
.____,ooo____.
,d#MMMMMMMMMMMMMMMMMM#o.
|MMMMMMMMMMMMMMMMMMMMMMMM
|MMMMMMMMMMMMMMMMMMMMMMMM
|MMMMMMMMMMMMMMMMMMH#*#**
|M'"""""""""""""'`
|M.
`ML
HP ##o#
|L TMP]
M . *&' . `
|, |dL.?-\.~b \:^ |
`| ` ` ' `` ,
H `
|.
`| |
M ,'
| |
|, |
|| |
J' |
M. J|
HM\\ -':|
`"=+\&#HMH#*??v/''
`""""`""
>
```
## Modifications
* ajouter une variable d'environnement `DRINKS_DIR` pour spécifier l'emplacement
de la réserve de picole.
* modifier la gestion des fichiers de picole afin d'avoir une description
succinte dans le listing du bar.
## Conteneur
Le serveur BaaS (Beverage as a Service) est dorénavant disponible sous forme de conteneur.
### Génération de l'image
Création de l'image `guinnessd:latest`
```bash
make -f Makefile.docker build
```
### Utilisation du conteneur
- Le service écoute sur le port `1664`.
- Le bar se situe dans `/usr/local/share/picoles` et est déjà approvionné. il est donc possible d'en faire un *volume Docker*.
```bash
docker run --rm -p 1664:1664 guinnessd:latest
```
### *Docker Swarm*
Ma préférence allant à l'utilisation de *Docker* via les *Docker Swarm*, vous touverez ci-dessous un fichier de *stack*
```yaml
version: 3.9
service:
guinnessd:
image: guinnessd:latest
logging:
driver: journald
options:
tag: "docker: guinnessd"
ports:
- target: 1664
published: 1664
mode: host
deploy:
endpoint_mode: dnsrr
mode: replicated
replicas: 1 # Multipliez les barmen en ajoutant des réplicas :-)
```

275
broadcast.c Normal file
View File

@@ -0,0 +1,275 @@
/*
* guinnessd
* architecture clients/serveur guinness : broadcast messages
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#include "defines.h"
#include "printlog.h"
#include "xmem.h"
#include "guinnessd.h"
#include "lists.h"
#include "tools.h"
#include "broadcast.h"
#include "drinks.h"
pthread_mutex_t mutex_broadcast;
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 ? "TOURNEE" :
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 ("Recu : ID = %s\n", token);
#endif
/* type */
token = strtok_r (NULL, SEP, &saveptr);
#ifdef DEBUG
printf ("Recu : TYPE = %s\n", token);
#endif
*t = atoi (token);
/* from */
token = strtok_r (NULL, SEP, &saveptr);
#ifdef DEBUG
printf ("Recu : FROM = %s\n", token);
#endif
*f = NULL;
if (token) *f = xstrdup (token);
/* message */
token = strtok_r (NULL, SEP, &saveptr);
#ifdef DEBUG
printf ("Recu : 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 element. 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 ? "TOURNEE" :
type == 3 ? "MESSAGE" :
"ERREUR");
printlog (LOG_NOTIFY, " de [%s] : %s\n", from, mesg ? mesg : "RIEN");
switch (type) {
case QUITTER: /* Un utilisateur se deconnecte */
snprintf (datas, MAXSTRLEN - 1, "Deconnexion de [%s] : %s",
from, mesg);
break;
case TOURNEE: /* Tournee generale */
if (mesg == NULL) {
snprintf (head, MAXSTRLEN - 1,
" -+- Tournee generale offerte par %s ! -+-",
from);
breuv = drinks_get (infos->prefb);
} else {
snprintf (head, MAXSTRLEN - 1,
" -+- Tournee 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 supporte.\n");
type = -1;
}
if (from) free (from);
if (mesg) free (mesg);
if (type != -1) cont = send_infos (socket_service, datas);
return cont;
}

196
clients.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* clients
* architecture clients/serveur guinness : clients list
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#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 elements :\n"
"nom : %d [%s]\n"
"biere : %d [%s]\n"
"date : %d [%s]\n"
"hote : %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) connecte(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) connecte(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);
/* biere */
token = strtok_r (NULL, SEP, &saveptr);
if (token) biere = xstrdup (token);
/* date */
token = strtok_r (NULL, SEP, &saveptr);
if (token) date = xstrdup (token);
/* hote */
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 ("Biere : ");
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 ("Hote : ");
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"
"Biere : %s\n"
"Connexion : %s\n",
nom ? nom : "-",
biere ? biere : "-",
date ? date : "-");
if (admin)
sprintf (datas, "%s"
"Hote : %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;
}

446
commands.c Normal file
View File

@@ -0,0 +1,446 @@
/*
* commands
* architecture clients/serveur guinness
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#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 connectes", FALSE, FALSE, FALSE, f_list},
{"blist", "liste des boissons disponibles", FALSE, FALSE, FALSE, f_bevr},
{"round", "tournee generale (boisson en option ou preferee)",
TRUE, FALSE, FALSE, f_turn},
{"cold", "la guinness est servie a - de 10C, sinon entre 12 et 15",
FALSE, FALSE, FALSE, f_cold},
{"msg", "message a 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 a recevoir (boisson en option ou "
"preferee)", FALSE, FALSE, TRUE, f_glas},
{"admin", "passer en mode administration", TRUE, FALSE, FALSE, f_sadm},
{"33", "arreter le serveur", FALSE, TRUE, FALSE, f_shut},
{"add", "ajoute un utilisateur dans la liste des habitues",
TRUE, TRUE, FALSE, f_addu},
{"del", "enleve un utilisateur de la liste des habitues",
TRUE, TRUE, FALSE, f_delu},
{"rldb", "recharge la liste des boissons", FALSE, TRUE, FALSE, f_rldb},
{"save", "sauve la liste des habitues", FALSE, TRUE, FALSE, f_save},
{"load", "charge la liste des habitues", 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 (precedees du caractere 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 (precedees du caractere 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, "Temperature normale.\n");
} else {
infos->cold = TRUE;
cont = send_infos (socket_service, "Temperature fraiche (10C).\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 tournee : %s\n",
breuv ? breuv : "prefere");
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 deja utilise !\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 desire : %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 etes 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'etes PLUS administrateur.\n");
}
return cont;
}
int f_shut (int socket_service, const char *commande, userinfos *infos) {
online = FALSE;
send_infos (socket_service, "Arret 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 rechargee...\n");
}
int f_addu (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implementee...\n");
}
int f_delu (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implementee...\n");
}
int f_save (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implementee...\n");
}
int f_load (int socket_service, const char *commande, userinfos *infos) {
return send_infos (socket_service, "Fonction non implementee...\n");
}

View File

@@ -24,7 +24,7 @@ typedef struct cmdslst {
int reply (int socket_service, char *commande, userinfos *infos); int reply (int socket_service, char *commande, userinfos *infos);
int send_servercmds (int socket_service); int send_servercmds (int socket_service);
/* Fonctions associées aux commandes */ /* Fonctions associees aux commandes */
int f_help (int socket_service, const char *commande, userinfos *infos); int f_help (int socket_service, const char *commande, userinfos *infos);
int f_quit (int socket_service, const char *commande, userinfos *infos); int f_quit (int socket_service, const char *commande, userinfos *infos);
int f_list (int socket_service, const char *commande, userinfos *infos); int f_list (int socket_service, const char *commande, userinfos *infos);

View File

@@ -1,6 +1,6 @@
/* /*
* defines * defines
* Création et manipulation de sockets * Creation et manipulation de sockets
* Thomas Nemeth -- le 15 juin 2001 * Thomas Nemeth -- le 15 juin 2001
* *
*/ */

126
drinks.c Normal file
View File

@@ -0,0 +1,126 @@
/*
* drinks
* architecture clients/serveur guinness
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#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, "Acces 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;
/* Element 0 (Guinness) disponible par defaut */
if (strcmp (nom, "guinness") == 0) breuvage = xstrdup (pinte);
/* Sinon on cherche dans la liste des fichiers :
* on commence a 1 pour eviter la pinte de Guinness qui est traitee
* 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 trouve => pinte par defaut */
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 repertoire [%s]\n", path);
#ifdef DEBUG
perror ("opendir ");
#endif
return;
}
printlog (LOG_NOTIFY, "Liste des fichiers a integrer :\n");
while ((dirinfos = readdir (rep)) != NULL) {
snprintf (filename, MAXSTRLEN, "%s/%s", path, dirinfos->d_name);
if (stat (filename, &fileinfos) == -1) {
printlog (LOG_ERROR, "Acces 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);
}
}

529
guinness.c Normal file
View File

@@ -0,0 +1,529 @@
/*
* guinness
* architecture clients/serveur guinness.
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#include "defines.h"
#include "xmem.h"
#include "guinness.h"
#include "tools.h"
#include "config.h"
#ifdef SunOS
char *crypt(const char *key, const char *salt);
#else
extern char *crypt __P ((__const char *__key, __const char *__salt));
#endif
/* VARIABLES GLOBALES */
char **commandes = NULL;
char *utilisateur = NULL;
char *boisson = NULL;
char *serveur = NULL;
char *prompt = NULL;
char *logout = NULL;
char cmdchr = 0;
int port = 0;
int nb_cmd = 0;
/*
* 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 *configfile;
char tmpstr[MAXSTRLEN + 1];
char *Home;
char *value;
Home = getenv ("HOME");
configfile = xmalloc ((strlen (Home) +
strlen (CONFIG_FILE) + 2) * sizeof (char));
snprintf (configfile, MAXSTRLEN, "%s/%s", Home, CONFIG_FILE);
/* Ouverture du fichier */
if ( (file = fopen (configfile, "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, "user=", 5) == 0) && (utilisateur == NULL) )
utilisateur = xstrdup (value);
if ( (strncmp (tmpstr, "server=", 7) == 0) && (serveur == NULL) )
serveur = xstrdup (value);
if ( (strncmp (tmpstr, "port=", 5) == 0) && (port == 0) )
port = atoi (value);
if ( (strncmp (tmpstr, "prompt=", 7) == 0) && (prompt == NULL) )
prompt = xstrdup (value);
if ( (strncmp (tmpstr, "pref=", 5) == 0) && (boisson == NULL) )
boisson = xstrdup (value);
if ( (strncmp (tmpstr, "cmdchr=", 7) == 0) && (cmdchr == 0) )
cmdchr = value[0];
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", configfile);
#endif
}
free (configfile);
}
/*
* Fonction de nettoyage
*
*/
void libere () {
if (utilisateur) free (utilisateur);
if (serveur) free (serveur);
if (boisson) free (boisson);
if (logout) free (logout);
}
/*
* Aide
*
*/
void Usage (int help) {
printf ("guinness by Thomas Nemeth - v %s (compilation %s : %s)\n",
VERSION, OS_TYPE, COMPIL_DATE);
if (help)
printf ("Usage : guinness [-h] [-v] [-m machine] "
"[-p port] [-u utilisateur] [-b boisson] [-q msgdx]\n"
" -h : aide sur les parametres\n"
" -v : affiche la version\n"
" -m machine : speficie le nom du serveur\n"
" -p port : specifie le numero du port\n"
" -u utilisateur : nom d'utilisateur\n"
" -b boisson : boisson preferee\n"
" -q msgdx : message d'au-revoir a la deconnexion\n"
" Online (precede du caractere de commande \"/\") :\n"
" help : affiche l'aide sur les commandes\n"
" quit : quitte\n\n");
libere ();
exit (1);
}
/*
* Traitement des arguments
*
*/
void traite_argv (int argc, char *argv[]) {
int option;
/* Verification des parametres */
while ((option = getopt (argc, argv, "hvm:p:u:b:q:")) != -1) {
switch (option) {
case 'h' :
Usage (TRUE);
break;
case 'v' :
Usage (FALSE);
break;
case 'm' :
SET_STRING (serveur, optarg);
break;
case 'p' :
port = atoi (optarg);
break;
case 'u' :
SET_STRING (utilisateur, optarg);
break;
case 'b' :
SET_STRING (boisson, optarg);
break;
case 'q' :
SET_STRING (logout, 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);
}
}
/*
* Envoi de commande
*
*/
int send_cmd (int socket_client) {
char clavier[MAXSTRLEN + 1];
char *commande;
char *admin_crypt;
int i, found = FALSE, cont = TRUE;
/* Lecture d'une commande au clavier */
memset (clavier, 0, MAXSTRLEN);
if ( (fgets (clavier, (int) MAXSTRLEN, stdin) == NULL) &&
feof (stdin) ) {
snprintf (clavier, MAXSTRLEN, "%cquit", cmdchr);
}
/* Determination du type (commande explicite / message) */
if (clavier[0] == cmdchr)
commande = xstrdup (clavier + 1);
else {
commande = xmalloc ((strlen (clavier) + 6) * sizeof (char));
snprintf (commande, strlen (clavier) + 6, "msg %s", clavier);
}
/* Suppression des retours a la ligne pour comparaison */
for (i = 0 ; i < strlen (commande) ; i++)
if (commande[i] == '\n') commande[i] = '\0';
/* Recherche de la bonne commande */
if (strlen (commande) > 0)
for (i = 0 ; i < nb_cmd ; i++) {
int cmp = -1;
if (commandes[i][0] == '*') /* Commandes d'administration */
cmp = strncmp (commandes[i]+1, commande,
strlen (commandes[i])-1);
else if (commandes[i][0] == '+') /* Commandes a intervalle */
cmp = ( (strchr (commandes[i]+1, commande[0]) != NULL) &&
( (strlen (commande) == 1) ||
(commande[1] == ' ') ) ) ? 0 : -1;
else { /* Commande simple : verification pour la commande entiere
* ou le premier caractere.
*/
cmp = (
/* comparaison exacte entre les deux commandes
*/
(strncmp (commandes[i], commande,
strlen (commandes[i]) ) == 0) ||
/* comparaison entre les 2 premieres lettres en
* cas de presence de parametres
*/
( (commandes[i][0] == commande[0]) &&
(commande[1] == ' ') ) ||
/* Comparaison entre les deux premieres lettres en cas
* de presence d'une unique lettre dans la commande
*/
( (commandes[i][0] == commande[0]) &&
(strlen (commande) == 1) ) ) ? 0 : -1;
/* Commande trouvee : si un seul caractere, remplacement par
* la commande complete.
*/
if ( (cmp == 0) &&
(strncmp (commandes[i], commande,
strlen (commandes[i]) ) != 0) ) {
char *tmpstr;
tmpstr = xmalloc ( (strlen (commande) +
strlen (commandes[i]) ) *
sizeof (char) );
strcpy (tmpstr, commandes[i]);
strcat (tmpstr, commande+1);
#ifdef DEBUG
printf ("Nouvelle commande = %s | %d\n",
tmpstr, strlen (tmpstr) );
#endif
if (strlen (tmpstr) > MAXSTRLEN) {
fprintf (stderr, "Commande trop longue !\n");
printf (prompt);
return TRUE; /* continue */
}
free (commande);
commande = xstrdup (tmpstr);
free (tmpstr);
}
#ifdef DEBUG
printf ("l = %c / c = %c ==> %d\n",
commandes[i][0], commande[0], cmp);
#endif
}
if (cmp == 0) {
#ifdef DEBUG
int j;
printf ("Commande reconnue : %s\n[%s (%d)] :",
commandes[i], commande, strlen (commande) );
for (j = 0 ; j < strlen (commande) ; j++)
printf (" %d", commande[j]);
printf ("\n");
#endif
found = TRUE;
}
}
if (! found) {
#ifdef DEBUG
fprintf (stderr, "Commande inconnue : [%s (%d)]",
commande, strlen (commande) );
for (i = 0 ; i < strlen (commande) ; i++)
fprintf (stderr, " %d", commande[i]);
fprintf (stderr, ".\n\n");
#else
fprintf (stderr, "Commande inconnue : [%s]\n", commande);
#endif
printf (prompt);
return TRUE; /* continue */
}
/* Mode administrateur */
if ( (strncmp (commande, "admin ", 6) == 0) && (strlen (commande) > 6) ) {
int taille;
admin_crypt = xstrdup (crypt (commande + 6, "Gs"));
free (commande);
taille = strlen ("admin ") + strlen (admin_crypt) + 1;
commande = xmalloc (taille);
snprintf (commande, taille, "admin %s", admin_crypt + 2);
}
cont = send_infos (socket_client, commande);
free (commande);
return cont;
}
void set_cmds (char *cmds) {
char *tok, *save;
int i = 0;
#ifdef DEBUG
int j;
#endif
nb_cmd = 0;
save = xstrdup (cmds);
#ifdef DEBUG
printf ("Commandes disponibles : \n");
/* printf ("%s\n", cmds); */
#endif
tok = strtok (save, "\n");
while (tok != NULL) {
nb_cmd++;
tok = strtok (NULL, "\n");
}
commandes = xmalloc ((nb_cmd) * sizeof (char*));
tok = strtok (cmds, "\n");
while (tok != NULL) {
commandes[i] = xstrdup (tok);
#ifdef DEBUG
if (tok[0] == '+') {
for (j = 1 ; j < strlen (commandes[i]) ; j++)
printf ("%c%c ", cmdchr, commandes[i][j]);
} else if (tok[0] != '*') {
printf ("%c%s ", cmdchr, commandes[i]);
}
#endif
i++;
tok = strtok (NULL, "\n");
}
printf ("\n");
free (save);
}
/*
* Fonction d'initialisation de la communication
*
*/
int initiate (int socket_client) {
char cmds[MAXSTRLEN];
char datas[MAXSTRLEN];
char nick_ok[MAXSTRLEN];
int cont = TRUE;
memset (datas, 0, MAXSTRLEN);
/* Reception de la liste des commandes */
cont = read_infos (socket_client, cmds);
if (cont) {
set_cmds (cmds);
snprintf (datas, MAXSTRLEN - 1, "%s\n%s\n%s",
utilisateur, boisson, logout);
/* Envoi des donnees utilisateur */
cont = send_infos (socket_client, datas);
read_infos (socket_client, nick_ok);
if (nick_ok[0] == '@') {
printf ("%s", nick_ok + 1);
return FALSE;
}
printf ("%s", nick_ok);
/* Traitement des commandes et des infos */
printf (prompt);
}
return cont;
}
/*
* Boucle de commande et de reception
*
*/
void data_rw (int socket_client) {
int cont = TRUE;
char infos[MAXSTRLEN];
fd_set lire;
cont = initiate (socket_client);
while (cont == TRUE) {
fflush (stdout);
/* Construction de l'ensemble a scruter en lecture : */
FD_ZERO (&lire);
FD_SET (STDIN_FILENO, &lire);
FD_SET (socket_client, &lire);
/* Attente d'un message sur la liste : */
select (socket_client + 1, &lire, NULL, NULL, NULL);
if (FD_ISSET (STDIN_FILENO, &lire) ) {
cont = send_cmd (socket_client);
} else {
int is;
cont = read_infos (socket_client, infos);
is = 0;
do {
printf ("%s\n", infos + is);
while (is < MAXSTRLEN && infos[is]) is ++;
/* on suppose qu'un seul '\0' separe deux messages */
is ++;
} while (is < MAXSTRLEN && infos[is]);
/* Hack pour faire afficher le message par xmessage
* Pas tres joli lors des deconnexions.
*/
/* if (getenv ("DISPLAY")) { */
/* if (! fork ()) */
/* execlp ("xmessage", "xmessage", infos, NULL); */
/* } */
fflush (stdout);
printf (prompt);
}
}
printf ("%s\n", logout);
close (socket_client);
}
/*
* Gestionnaire de signal SIGPIPE
*
*/
void handler_sigpipe (int sig) {
printf ("Signal SIGPIPE recu...\n");
}
/*
* Fonction principale
*
*/
int main (int argc, char *argv[]) {
int socket_client;
char *environ_user;
signal (SIGPIPE, handler_sigpipe);
/* Verification des parametres */
traite_argv (argc, argv);
/* Lecture du fichier de config */
load_config ();
/* Valeurs par defaut */
if (! utilisateur) {
environ_user = getenv ("USER");
if (environ_user && *environ_user)
utilisateur = xstrdup (environ_user);
else
utilisateur = xstrdup ("toto");
}
if (IS_NOT_GOOD (serveur)) SET_STRING (serveur, DEFAULT_SERVER);
if (IS_NOT_GOOD (prompt)) SET_STRING (prompt, DEFAULT_PROMPT);
if (IS_NOT_GOOD (boisson)) SET_STRING (boisson, DEFAULT_DRINK);
if (IS_NOT_GOOD (logout)) SET_STRING (logout, DEFAULT_LOGOUT);
if (cmdchr == 0) cmdchr = '/';
if (port == 0) port = DEFAULT_SERVER_PORT;
printf ("Serveur : [%s]\t", serveur);
printf ("Port : [%d]\n", port);
printf ("Utilisateur : [%s]\t", utilisateur);
printf ("\tBoisson : [%s]\t", boisson);
printf ("Logout : [%s]\n", logout);
printf ("Prefixe : [%c]\n", cmdchr);
/* Connexion au serveur */
if ( (socket_client = connect_server (serveur, port) ) == -1) {
fprintf (stderr, "Connexion refusee...\n");
return -1;
}
printf ("-+- Connexion acceptee. -+-\n");
data_rw (socket_client);
libere ();
return 0;
}

17
guinness.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* guinness
* architecture clients/serveur guinness.
* Thomas Nemeth -- le 15 juin 2001
*
*/
#ifndef GUINNESS_CLIENT
#define GUINNESS_CLIENT
#define CONFIG_FILE ".guinnessrc"
#define DEFAULT_SERVER "127.0.0.1"
#define DEFAULT_PROMPT "> "
#endif

View File

@@ -32,7 +32,9 @@
#include "commands.h" #include "commands.h"
#include "config.h" #include "config.h"
/* Config spécifique serveur */ pthread_mutex_t mutex_clients;
/* Config specifique serveur */
char *adr_ip = NULL; char *adr_ip = NULL;
int port = 0; int port = 0;
int online = TRUE; int online = TRUE;
@@ -45,7 +47,7 @@ FILE *outerr = NULL;
Elt *clients_list = NULL; Elt *clients_list = NULL;
Elt *drinks_list = NULL; Elt *drinks_list = NULL;
/* Config spécifique connexion des clients */ /* Config specifique connexion des clients */
char *pseudo = NULL; char *pseudo = NULL;
char *drink = NULL; char *drink = NULL;
char *logout = NULL; char *logout = NULL;
@@ -68,23 +70,23 @@ void install_handler ();
void handler_signaux (int sig) { void handler_signaux (int sig) {
switch (sig) { switch (sig) {
case SIGPIPE: case SIGPIPE:
printlog (LOG_NOTIFY, "Signal SIGPIPE reçu...\n"); printlog (LOG_NOTIFY, "Signal SIGPIPE recu...\n");
install_handler (); install_handler ();
break; break;
case SIGTERM: case SIGTERM:
case SIGQUIT: case SIGQUIT:
case SIGINT: case SIGINT:
online = FALSE; online = FALSE;
printlog (LOG_NOTIFY, "Signal de terminaison reçu...\n"); printlog (LOG_NOTIFY, "Signal de terminaison recu...\n");
break; break;
default: default:
printlog (LOG_NOTIFY, "Signal reçu...\n"); printlog (LOG_NOTIFY, "Signal recu...\n");
} }
} }
/* /*
* Lecture du fichier de config : récupération des valeurs * Lecture du fichier de config : recuperation des valeurs
* *
*/ */
char *get_string_from_token (char *line) { char *get_string_from_token (char *line) {
@@ -154,13 +156,13 @@ void Usage (int help) {
if (help) if (help)
printf ("Usage : guinnessd [-h] [-v] [-b] [-p port] " printf ("Usage : guinnessd [-h] [-v] [-b] [-p port] "
"[-s passwd] [-d chemin] [-l fichier] [-f fichier]\n" "[-s passwd] [-d chemin] [-l fichier] [-f fichier]\n"
" -h : aide sur les paramètres\n" " -h : aide sur les parametres\n"
" -v : affiche la version\n" " -v : affiche la version\n"
" -b : détache le serveur du terminal\n" " -b : detache le serveur du terminal\n"
" -a adresse : spécifie l'adresse du serveur\n" " -a adresse : specifie l'adresse du serveur\n"
" -p port : spécifie le numéro du port\n" " -p port : specifie le numero du port\n"
" -s passwd : spécifie le mot de passe d'aministration\n" " -s passwd : specifie le mot de passe d'aministration\n"
" -d chemin : indique le chemin où se" " -d chemin : indique le chemin ou se"
" trouvent les ascii-arts\n" " trouvent les ascii-arts\n"
" -l fichier : fichier de log\n" " -l fichier : fichier de log\n"
" -f fichier : fichier de configuration\n\n"); " -f fichier : fichier de configuration\n\n");
@@ -176,7 +178,7 @@ int traite_argv (int argc, char *argv[]) {
int option; int option;
int detach = FALSE; int detach = FALSE;
/* Vérification des paramètres */ /* Verification des parametres */
while ((option = getopt (argc, argv, "hvba:p:s:d:l:f:")) != -1) { while ((option = getopt (argc, argv, "hvba:p:s:d:l:f:")) != -1) {
switch (option) { switch (option) {
case 'h' : case 'h' :
@@ -260,7 +262,7 @@ int initiate (int socket_service, userinfos *infos) {
memset (userdatas, 0, MAXSTRLEN); memset (userdatas, 0, MAXSTRLEN);
/* Récupération des infos sur le connecté */ /* Recuperation des infos sur le connecte */
get_sock_infos (socket_service, get_sock_infos (socket_service,
&nom_distant, &ip_distant, &nom_distant, &ip_distant,
&port_local, &port_distant); &port_local, &port_distant);
@@ -284,18 +286,18 @@ int initiate (int socket_service, userinfos *infos) {
if ( (cont = send_servercmds (socket_service)) == FALSE) if ( (cont = send_servercmds (socket_service)) == FALSE)
return cont; return cont;
/* 2. attente des données du connecté */ /* 2. attente des donnees du connecte */
if ( (cont = read_infos (socket_service, userdatas)) == FALSE) if ( (cont = read_infos (socket_service, userdatas)) == FALSE)
return cont; return cont;
/* FIN DU PROTOCOLE : Véricifations / ajout dans la liste / affichage */ /* FIN DU PROTOCOLE : Vericifations / ajout dans la liste / affichage */
datas = xstrdup (userdatas); datas = xstrdup (userdatas);
/* Nom d'utilisateur */ /* Nom d'utilisateur */
token = strtok_r (datas, delim, &saveptr); token = strtok_r (datas, delim, &saveptr);
snprintf (infos->nom, MAXSTRLEN, "%s", token ? token : pseudo); snprintf (infos->nom, MAXSTRLEN, "%s", token ? token : pseudo);
/* Boisson préférée */ /* Boisson preferee */
token = strtok_r (NULL, delim, &saveptr); token = strtok_r (NULL, delim, &saveptr);
snprintf (infos->prefb, MAXSTRLEN, "%s", token ? token : drink); snprintf (infos->prefb, MAXSTRLEN, "%s", token ? token : drink);
@@ -309,17 +311,17 @@ int initiate (int socket_service, userinfos *infos) {
strftime (infos->cxdate, MAXSTRLEN, "%a %d %b %Y %T", today); strftime (infos->cxdate, MAXSTRLEN, "%a %d %b %Y %T", today);
printlog (LOG_NOTIFY, "Utilisateur : [%s]\n", infos->nom); printlog (LOG_NOTIFY, "Utilisateur : [%s]\n", infos->nom);
printlog (LOG_NOTIFY, "Boisson préférée : [%s]\n", infos->prefb); printlog (LOG_NOTIFY, "Boisson preferee : [%s]\n", infos->prefb);
printlog (LOG_NOTIFY, "Message de logout : [%s]\n", infos->logout); printlog (LOG_NOTIFY, "Message de logout : [%s]\n", infos->logout);
printlog (LOG_NOTIFY, "Date de connexion : [%s]\n", infos->cxdate); printlog (LOG_NOTIFY, "Date de connexion : [%s]\n", infos->cxdate);
pthread_mutex_lock (&mutex_clients); pthread_mutex_lock (&mutex_clients);
if (exist_elt (clients_list, infos->nom)) { if (exist_elt (clients_list, infos->nom)) {
char nick_ok[MAXSTRLEN]; char nick_ok[MAXSTRLEN+1];
snprintf (nick_ok, MAXSTRLEN, "@%s", infos->nom); snprintf (nick_ok, MAXSTRLEN, "@%s", infos->nom);
snprintf (infos->nom, MAXSTRLEN, "%s", nick_ok); snprintf (infos->nom, MAXSTRLEN, "%s", nick_ok);
send_infos (socket_service, "@Pseudo déjà utilisé !\n"); send_infos (socket_service, "@Pseudo deja utilise !\n");
printlog (LOG_NOTIFY, "Pseudo déjà utilisé => %s\n", infos->nom); printlog (LOG_NOTIFY, "Pseudo deje utilise => %s\n", infos->nom);
pthread_mutex_unlock (&mutex_clients); pthread_mutex_unlock (&mutex_clients);
return FALSE; return FALSE;
} }
@@ -329,8 +331,8 @@ int initiate (int socket_service, userinfos *infos) {
if (! exist_elt (drinks_list, infos->prefb)) if (! exist_elt (drinks_list, infos->prefb))
send_infos (socket_service, send_infos (socket_service,
"Votre boisson préférée n'est pas disponible sur ce" "Votre boisson preferee n'est pas disponible sur ce"
" serveur !\nVous aurez des Guinness à la place.\n"); " serveur !\nVous aurez des Guinness a la place.\n");
/* Passage en mode non bloquant */ /* Passage en mode non bloquant */
fcntl (socket_service, F_SETFL, O_NONBLOCK); fcntl (socket_service, F_SETFL, O_NONBLOCK);
@@ -369,13 +371,13 @@ void thread_service (int *sock_serv) {
} }
#ifdef DEBUG #ifdef DEBUG
printlog (LOG_NOTIFY, "Prêt à recevoir des commandes.\n"); printlog (LOG_NOTIFY, "Pret a recevoir des commandes.\n");
#endif #endif
while (cont == TRUE) { while (cont == TRUE) {
memset (commande, 0, MAXSTRLEN + 1); memset (commande, 0, MAXSTRLEN + 1);
/* Lecture des caractères reçus */ /* Lecture des caracteres recus */
do { do {
sleep (1); sleep (1);
nb = read (socket_service, commande, MAXSTRLEN); nb = read (socket_service, commande, MAXSTRLEN);
@@ -384,7 +386,7 @@ void thread_service (int *sock_serv) {
if ( (errno == EPIPE) || (nb == 0) ) { if ( (errno == EPIPE) || (nb == 0) ) {
cont = FALSE; cont = FALSE;
} else { } else {
printlog (LOG_ERROR, "Erreur de connexion réception !\n"); printlog (LOG_ERROR, "Erreur de connexion reception !\n");
} }
} }
} while ( (cont != FALSE) && } while ( (cont != FALSE) &&
@@ -392,7 +394,7 @@ void thread_service (int *sock_serv) {
(new_message (old_id) != TRUE) ); (new_message (old_id) != TRUE) );
#ifdef DEBUG #ifdef DEBUG
printlog (LOG_NOTIFY, "Commande reçue.\n"); printlog (LOG_NOTIFY, "Commande recue.\n");
#endif #endif
if (cont == TRUE) { if (cont == TRUE) {
/* Traitement de la commande */ /* Traitement de la commande */
@@ -403,7 +405,7 @@ void thread_service (int *sock_serv) {
old_id = get_broadcastid (); old_id = get_broadcastid ();
cont = send_broadcast (socket_service, &infos); cont = send_broadcast (socket_service, &infos);
#ifdef DEBUG #ifdef DEBUG
printlog (LOG_ERROR, "Émission broadcast pour %s (id = %ld)\n", printlog (LOG_ERROR, "Emission broadcast pour %s (id = %ld)\n",
infos.nom, old_id); infos.nom, old_id);
#endif #endif
} }
@@ -436,20 +438,30 @@ void install_handler () {
/* /*
* Initialisation générale * Initialisation generale
* *
*/ */
void guinnessd_init (int argc, char *argv[]) { void guinnessd_init (int argc, char *argv[]) {
pthread_mutexattr_t mutex_attr; pthread_mutexattr_t mutex_attr;
char *cptr;
setlocale (LC_ALL, ""); setlocale (LC_ALL, "");
install_handler (); install_handler ();
/* Valeurs par défaut */ /* Valeurs par defaut */
logfile = stdout; logfile = stdout;
outerr = stderr; outerr = stderr;
/* Traitement des paramètres */ /* 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) { if (traite_argv (argc, argv) == TRUE) {
switch (fork()) { switch (fork()) {
case -1: /* erreur */ case -1: /* erreur */
@@ -458,7 +470,7 @@ void guinnessd_init (int argc, char *argv[]) {
case 0: /* le fils */ case 0: /* le fils */
setsid (); setsid ();
break; break;
default: /* le père */ default: /* le pere */
exit (0); exit (0);
} }
} }
@@ -466,12 +478,12 @@ void guinnessd_init (int argc, char *argv[]) {
/* Lecture du fichier de configuration */ /* Lecture du fichier de configuration */
load_config (); load_config ();
/* Initialisation des sémaphores */ /* Initialisation des semaphores */
pthread_mutexattr_init (&mutex_attr); pthread_mutexattr_init (&mutex_attr);
pthread_mutex_init (&mutex_broadcast, &mutex_attr); pthread_mutex_init (&mutex_broadcast, &mutex_attr);
pthread_mutex_init (&mutex_clients, &mutex_attr); pthread_mutex_init (&mutex_clients, &mutex_attr);
/* Affectation des paramètres */ /* Affectation des parametres */
if (IS_NOT_GOOD (pseudo)) SET_STRING (pseudo, DEFAULT_PSEUDO); if (IS_NOT_GOOD (pseudo)) SET_STRING (pseudo, DEFAULT_PSEUDO);
if (IS_NOT_GOOD (drink)) SET_STRING (drink, DEFAULT_DRINK); if (IS_NOT_GOOD (drink)) SET_STRING (drink, DEFAULT_DRINK);
if (IS_NOT_GOOD (logout)) SET_STRING (logout, DEFAULT_LOGOUT); if (IS_NOT_GOOD (logout)) SET_STRING (logout, DEFAULT_LOGOUT);
@@ -488,7 +500,7 @@ void guinnessd_init (int argc, char *argv[]) {
/* Option pour le buffer de logs */ /* Option pour le buffer de logs */
setvbuf (logfile, NULL, _IOLBF, 0); setvbuf (logfile, NULL, _IOLBF, 0);
/* Création de la liste de boissons par défaut*/ /* Creation de la liste de boissons par defaut*/
add_elt (&drinks_list, "guinness"); add_elt (&drinks_list, "guinness");
if (! chemin) chemin = xstrdup (DRINKS_DIR); if (! chemin) chemin = xstrdup (DRINKS_DIR);
@@ -504,13 +516,13 @@ void guinnessd_init (int argc, char *argv[]) {
int main (int argc, char *argv[]) { int main (int argc, char *argv[]) {
int socket_ecoute; int socket_ecoute;
int socket_service; int socket_service;
int lg_adresse = sizeof (struct sockaddr_in); socklen_t lg_adresse = sizeof (struct sockaddr_in);
struct sockaddr_in adresse; struct sockaddr_in adresse;
pthread_t pthread_id; pthread_t pthread_id;
guinnessd_init (argc, argv); guinnessd_init (argc, argv);
/* Installation de l'écoute du serveur */ /* Installation de l'ecoute du serveur */
if ( (socket_ecoute = install_server (port, adr_ip, NULL)) == -1) { if ( (socket_ecoute = install_server (port, adr_ip, NULL)) == -1) {
printlog (LOG_ERROR, "Impossible d'installer le service.\n"); printlog (LOG_ERROR, "Impossible d'installer le service.\n");
return -1; return -1;
@@ -548,21 +560,21 @@ int main (int argc, char *argv[]) {
return -1; return -1;
} }
/* Ici connexion acceptée */ /* Ici connexion acceptee */
printlog (LOG_NOTIFY, "Connexion acceptée...\n"); printlog (LOG_NOTIFY, "Connexion acceptee...\n");
/* Lancement d'une activité de traitement */ /* Lancement d'une activite de traitement */
if (pthread_create (&pthread_id, NULL/*pthread_attr_default*/, if (pthread_create (&pthread_id, NULL/*pthread_attr_default*/,
(void *) thread_service, (void *) thread_service,
(void *) &socket_service) == -1) { (void *) &socket_service) == -1) {
printlog (LOG_ERROR, "Erreur création thread de service.\n"); printlog (LOG_ERROR, "Erreur creation thread de service.\n");
close (socket_service); close (socket_service);
} }
/* fflush (logfile); */ /* fflush (logfile); */
sleep (2); sleep (2);
} }
printlog (LOG_NOTIFY, "Arrêt du serveur demandé.\n"); printlog (LOG_NOTIFY, "Arret du serveur demande.\n");
/* fflush (logfile); */ /* fflush (logfile); */
close (socket_ecoute); close (socket_ecoute);

View File

@@ -26,12 +26,12 @@ typedef struct userinfos {
int port; int port;
int admin; int admin;
int cold; int cold;
int comm[2]; /* Pas encore utilisé */ int comm[2]; /* Pas encore utilise */
} userinfos; } userinfos;
pthread_mutex_t mutex_broadcast; extern pthread_mutex_t mutex_broadcast;
pthread_mutex_t mutex_clients; extern pthread_mutex_t mutex_clients;
#endif #endif

187
lists.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* lists
* architecture clients/serveur guinness
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#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;
}

23
picoles/canabis Normal file
View File

@@ -0,0 +1,23 @@
.:.
:|:
.:|:.
::|::
:. ::|:: .:
:|:. .::|::. .:|:
::|:. :::|::: .:|:;
`::|:. :::|::: .:|::'
::|::. :::|::: .::|:;
`::|::. :::|::: .::|::'
:::|::. :::|::: .::|::;
`:::|::. :::|::: .::|::;'
`::. `:::|::. :::|::: .::|::;' .:;'
`:::.. `:::|::. :::|::: .::|::;' ..::;'
`::::::. `:::|::. :::|::: .::|::;' .:::::;'
`::::::.`:::|::.:::|::;.::|::;'.:::::;'
`::::::.`::|::.::|::.::|::'.:::::;'
`:::::::::|:::|:::|::::::::;'
``:::::::|:|::|:::::;''
`::::::::::;'
.:;'' ::: ``::.
: : :
':`

25
picoles/champagne Normal file
View File

@@ -0,0 +1,25 @@
o oo" " "
o o o"" "o
o" M "
"o " o M ""
M "o" MoMo
"" o o"oo
M"o "o" M
oMoo" Mo"
M"o "M MM
"o"o"o M
"oM"oMMo
M "M M
"M"oM"
M o
o o
o
" o
Mo
o
"o
"o
MMo
oM"o o
oo M"ooM"MoMoo
" " "

18
picoles/pastis Normal file
View File

@@ -0,0 +1,18 @@
+----------------+
|__ _____ |
|/~|~~|~~~/~|~~~~|
| \| | /\ | |
|-555555---- 1 |
| 55 111 |
| 55 1 11 |
| 5555 11 |
| 555 11 |
| 55 11 |
| 55 11 |
| 555555 111111 |
| |
| Le Pastis |
| |
|================|
| |
+----------------+

22
picoles/steinlager Normal file
View File

@@ -0,0 +1,22 @@
.sssssssss.
.sssssssssssssssssss
sssssssssssssssssssssssss
ssssssssssssssssssssssssssss
@@sssssssssssssssssssssss@ss
|s@@@@sssssssssssssss@@@@s|s
_______|sssss@@@@@sssss@@@@@sssss|s
/ sssssssss@sssss@sssssssss|s
/ .------+.ssssssss@sssss@ssssssss.|
/ / |...sssssss@sss@sssssss...|
| | |.......sss@sss@ssss......|
| | |..........s@ss@sss.......|
| | |...........@ss@..........|
\ \ |............ss@..........|
\ '------+...........ss@...........|
\________ .........................|
|.........................|
/...........................\
|.............................|
|.......................|
|...............|

41
pint.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* pint
* architecture clients/serveur guinness
* Thomas Nemeth -- le 15 juin 2001
*
*/
#ifndef GUINNESS_SERVER_PINT
#define GUINNESS_SERVER_PINT
char *pinte =
" .____,ooo____.\n"
" ,d#MMMMMMMMMMMMMMMMMM#o.\n"
" |MMMMMMMMMMMMMMMMMMMMMMMM\n"
" |MMMMMMMMMMMMMMMMMMMMMMMM\n"
" |MMMMMMMMMMMMMMMMMMH#*#**\n"
" |M'\"\"\"\"\"\"\"\"\"\"\"\"\"'`\n"
" |M.\n"
" `ML\n"
" HP ##o#\n"
" |L TMP]\n"
" M . *&' . `\n"
" |, |dL.?-\\.~b \\:^ |\n"
" `| ` ` ' `` ,\n"
" H `\n"
" |.\n"
" `| |\n"
" M ,'\n"
" | |\n"
" |, |\n"
" || |\n"
" J' |\n"
" M. J|\n"
" HM\\\\ -':|\n"
" `\"=+\\&#HMH#*??v/''\n"
" `\"\"\"\"`\"\"\n";
#endif

54
printlog.c Normal file
View File

@@ -0,0 +1,54 @@
/*
* printlog
* architecture clients/serveur guinness
* Thomas Nemeth / Arnaud Giersch -- le 23 aout 2001
*
*/
#include <stdio.h>
#include <time.h>
#ifdef SunOS
#include <sys/varargs.h>
#else
#include <stdarg.h>
#endif
#include <string.h>
#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);
}

View File

@@ -1,7 +1,7 @@
/* /*
* printlog * printlog
* architecture clients/serveur guinness * architecture clients/serveur guinness
* Thomas Nemeth / Arnaud Giersch -- le 23 août 2001 * Thomas Nemeth / Arnaud Giersch -- le 23 aout 2001
* *
*/ */

297
tools.c Normal file
View File

@@ -0,0 +1,297 @@
/*
* tools
* Creation et manipulation de sockets
* Thomas Nemeth -- le 15 juin 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include "defines.h"
#include "xmem.h"
#include "tools.h"
/*
* Ouverture d'une socket de type flot de donnees
*
* creation 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;
/*
* Creation 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;
}
/*
* Preparation 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 a la socket de connexion.\n"
"Attendez quelques minutes avant de relancer.\n");
#endif
perror (__FILE__ " bind");
close (desc_soc);
return -1;
}
/*
* Recuperation 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 ou se trouve le serveur */
if ( (serveur = gethostbyname (machine) ) == NULL) {
#ifdef DEBUG
fprintf (stderr, "Machine %s inconnue...\n", machine);
#endif
return -1;
}
/* Creation 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, "Creation de la socket du client impossible.\n");
#endif
return -1;
}
/* Preparation 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, "Creation de la socket du serveur impossible.\n");
#endif
return -1;
}
/* Declaration 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 reception de donnees
*
*/
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 reception !\n");
#endif
if ( (errno == EPIPE) || (nb == 0) ) return FALSE; /* cont = FALSE; */
}
#ifdef DEBUG
printf ("Recu : [%s] lg = %d/%d\n", infos, strlen (infos), nb);
#endif
return TRUE;
}
/*
* Fonction d'emisson de donnees
*
*/
int send_infos (int socket_data, const char *infos) {
#ifdef DEBUG
printf ("Emission 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 emission !\n");
#endif
if (errno == EPIPE) return FALSE; /*cont = FALSE;*/
}
#ifdef DEBUG
fprintf (stderr, "Emission 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'echecs */
*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 recuperation 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 recuperation 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'hote distant ");
#endif
return;
}
*nom = xstrdup (machine->h_name);
}

View File

@@ -1,6 +1,6 @@
/* /*
* tools * tools
* Création et manipulation de sockets * Creation et manipulation de sockets
* Thomas Nemeth -- le 15 juin 2001 * Thomas Nemeth -- le 15 juin 2001
* *
*/ */

31
xmem.c Normal file
View File

@@ -0,0 +1,31 @@
/*
* xmem
* architecture clients/serveur guinness : gestion memoire
* Thomas Nemeth -- le 24 aout 2001
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#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;
}

4
xmem.h
View File

@@ -1,7 +1,7 @@
/* /*
* xmem * xmem
* architecture clients/serveur guinness : gestion mémoire * architecture clients/serveur guinness : gestion memoire
* Thomas Nemeth -- le 24 août 2001 * Thomas Nemeth -- le 24 aout 2001
* *
*/ */