YooGoo

 
 
Bienvenue sur YooGoo
 
 

 
 
News

Description du Projet
Avancement du Projet
L'équipe
Photos du Projet et du reste
 
 

 
 
Téléchargement

Le Client
Le Serveur
Les Sources Serveur
Les Sources Client
Cahiers des Charges
Soutenance 1
Soutenance 2
Soutenance 3
Soutenance Finale
 
 

 
 
Contacts

Franck Tetzlaff CV Tessari Marco CV Bouhelier Stéphane CV Pouiller Jérôme CV
 
 

 
 

\includegraphics{YooGoo-Line.eps}
Rapport de première soutenance

BOUHELIER Stéphane alias Folkensama (Spé C1)
POUILLER Jérôme alias Hargos (Spé C1)
TESSARI Marco alias Zapata (Spé C1)
TETZLAFF Franck alias Danao (Spé C1)

EPITA - Janvier 2002


Table des matières

Introduction

Description

De nos jours, le chat occupe une grande partie de l'Internet, on y trouve une grande communauté de chatteurs. Malheureusement les logiciels actuellement disponibles ne nous satisfont pas pleinement. C'est pourquoi nous avons décidé de créer notre propre serveur chat avec un protocole qui lui est propre ainsi qu'une nouvelle communauté : The YooGooe Community. En effet notre projet qui sera intitulé YooGoo (en hommage à Timothée Gustave qui disait qu'il faut lutter contre la différence et non l'indifférence !!!) Plus sérieusement, YooGoo, ne signifie rien de spécial, c'est un mot sorti tout droit de l'esprit épitéen de ses concepteurs. Nous nous sommes un peu inspiré de Google et de Yahoo! Ce nom a le mérite d'être facile á retenir. De plus YooGoo.com était un des rares noms de domaine disponibles. YooGoo est un projet de chat sécurisé complet. Il intègrera un client et un serveur. Nous devrons aussi pour les besoins du projet recréer un protocole.

État du projet

Nous avions déjà beaucoup réfléchit lors de la conception du cahier des charges sur l'architecture de YooGoo. Ainsi, nous n'avons aucun changements à faire sur le cahier des charges. Pour la première soutenance, le planning a été bien fait, puisque nous ne sommes en retard sur aucun point. Nous avons tout d'abord appris les différents langages qui nous sont utiles : C++ mais aussi HTML/PHP/SQL. Comme prévu, le site web est prêt. Les scripts PHP permettent un entretient rapide. Nous avons rédigé la conception du protocole de YooGoo. Nous avons codé la classe des AVLs (ajout/suppression/recherche/etc.). Pour la première soutenance, nous devions concevoir la structure des objets User et Canal. Nous avons été plus loin en codant une bonne partie des procédures associées aux objets User et Canal. L'initialisation de la connexion sécurisée est totalement achevée alors qu'elle était prévue pour la seconde soutenance. Pour la prochaine soutenance, conformément au planning, nous continuerons sur notre lancée en intégrant les AVL au reste du serveur. Nous devrons gérer les threads des objets User et Canal. Il nous faudra aussi implémenter le parseur et les commandes de gestion d'utilisateur du protocole.

Qui a fait quoi?

Danao
a réalisé la classe canal et la classe user.
Folkensama
a travaillé sur la classe base de donné et a implémenté les types abstraits (pile, file, AVL ...).
Hargos
a conçu le protocole et est le webmaster du site www.YooGoo.com.
Zapata
s'est occupé du serveur (Winsock, cryptage, ...) et est l'administrateur de la machine YooGoo.

Base du serveur

Le cryptage des données

Récapitulatif

Comme indiqué dans le cahier des charges, l'un des atouts majeurs de YooGoo est qu'il sera sécurisé. La couche de sécurité la plus importante est le cryptage des messages circulants sur le réseau.
Il existe plusieurs algorithmes de cryptage. Les plus simples et les plus anciens sont les algorithmes secrets. Ce sont des algorithmes dont on ne connaît pas le procédé de cryptage. Il est tenu secret. Cette méthode ne nous convient pas, car les sources de notre projet sont disponibles pour tous les utilisateurs, donc l'algorithme de cryptage ne sera pas secret. Il existe alors des algorithmes à clé. L'algorithme est alors connu de tous mais la clé doit rester secrète car c'est d'elle que dépend la sécurité du message. Ceci permet de pouvoir utiliser un même algorithme autant de fois que l'on veut, car la sécurité ne dépend pas du procédé mais de la clé. C'est donc cette méthode qui a été retenue pour YooGoo. On distingue alors deux types de cryptage à clé. Les algorithmes symétriques et asymétriques.
Le cryptage symétrique, et en particulier le DES (Data Encryption Standard) que nous utiliserons, a besoin d'une seule clé pour crypter et décrypter le message. Cette clé doit alors être tenue secrète et les deux parties communicantes doivent derenir la clé. L'avantage est que ces algorithmes sont assez rapides et permettent le cryptage d'un grand nombre de données. Mais l'inconvénient est que les deux parties doivent detenir la clé. Dans notre cas cela implique l'échange de la clé entre le client et le serveur. Il faut donc trouver une autre méthode pour cet échange. De plus le DES est devenu peu sûr à cause des machines très puissantes actuelles. Nous utiliserons alors un triple-DES qui revient à crypter 3 fois le message (et donc avoir 2 ou 3 clés). Dans YooGoo on utilisera donc le DES pour crypter les messages entre les clients et le serveur.
Le cryptage asymétrique, et en particulier le RSA, fonctionne sur un principe de clé publique et de clé privée. On appelle clé publique la clé qui est accessible à tout le monde et qui permet de crypter les messages. La clé privée, qui elle doit être tenue secrète, sert à décrypter le message. On s'aperçoit alors que tout le monde peut crypter un message et que seulement une personne peut le décrypter. Ainsi, il est parfois impossible de savoir de qui provient le message. De plus le RSA se base sur des propriétés arithmétiques qui exigent des calculs sur de très grands nombres (pour que l'algorithme soit suffisamment sûr), ce qui fait que le temps de cryptage est beaucoup plus long que des algorithmes tels que le DES. Par conséquand le RSA sera seulement utilisé pour l'échange de la clé entre le serveur et les clients.

Le DES

Principe:

DES est un chiffrement par bloc, ce qui signifie qu'il traite les données en sections de taille fixe, appelées blocs. La taille d'un bloc DES est de 64 bits ; si le volume de données à chiffrer n'est pas un multiple pair de 64 bits, les données sont complétées d'une façon dépendante de l'application (par des '$\backslash$0' dans YooGoo).
La sécurité du DES repose sur le même principe qu'un écran de fumée ou, en jargon cryptographique, sur les principes de confusion et de diffusion. Le but de la confusion est de cacher toute relation existante entre le texte clair, le texte chiffré et la clé. Le but de la diffusion est de répartir les effets conjugués du texte clair et de la clé sur la plus grande longueur possible de texte chiffré. Ces deux principes rendent l'analyse cryptographique très difficile.
Avec DES, on chiffre un bloc de texte clair en réalisant une série de permutations et de substitutions sur celui-ci. Leur conséquence sur le texte clair est essentiellement fonction des 16 sous-clés, $K_1$, $K_2$, ... , $K_{16}$, dérivées d'une clé de départ, $K_0$ qui est celle que l'on fournit. Pour chiffrer un bloc de texte clair, les sous clés sont appliquées tour à tour ($K_1$, $K_2$, ..., $K_{16}$) sur les données à l'aide d'une suite d'opérations répétées 16 fois par clé. Chaque itération s'appelle un round. Le déchiffrement d'un bloc crypté s'effectue de la même façon, mais en appliquant les clés en sens inverse ($K_{16}$, $K_{15}$, ..., $K_1$).
Tous les tableaux utilisés lors des décalages, permutations, transformations et rotations, sont établis par une norme DES pour que l'algorithme ai une confusion et une dispersion maximum. La description de l'algorithme est très fastidieuse car les opérations effectuées peuvent sembler sorties de nulle part (c'est d'ailleurs un peu le cas).

Calcul des sous-clés

La première étape consiste à calculer les sous-clés à partir de la clé de départ. DES utilise une clé de 56 bits, mais nous en fournissons une de 64 bits car, car les 8 bits restants sont utilisés dans les implémentations matérielles du DES. Pour obtenir la clé de 56 bits, on effectue une transformation de clé selon le tableau Des_Transform[].
        // Correspondances pour la transformation de la clé
        static const int Des_Transform[56] =
        {
            57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
            10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
            63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
            14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
        };
Chaque position $p$ du tableau contient la position du bit de la clé de départ occupant la position $p$ de la clé transformée. Le bit 57 de la clé de départ, devient par exemple le bit 1 de la clé transformée ; de même, le bit 49 devient le bit 2, et ainsi de suite. La convention est de numéroter les bits de gauche à droite, en commençant à 1.
Après avoir transformé la clé en 56 bits, on calcule les sous-clés en divisant d'abord la clé en deux blocs de 28 bits. Puis, pour chaque sous-clé, on effectue une rotation des deux blocs d'un nombre de fois dépendant du round dans lequel on utilisera la sous-clé selon le tableau Des_Rotations[], puis on réunit les blocs.
        // Nombre de rotations pour le calcul des sous-clés
        static const int Des_Rotations[16] =
        {
        1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
        };
Après cela on réduit les sous-clés de 56 bits, formées des blocs réunis, à 48 bits en les permutant selon le tableau Des_Permute[].
        // Correspondances pour le choix permuté des sous-clés
        static const int Des_Permute[48] =
        {
        14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
        23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
        41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
        44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
        };
Cette permutation s'appelle "choix permuté". Ce traitement est répété pour chacune des 16 sous-clés. Le but de tout cela est de s'assurer que l'ont peut appliquer, dans chaque round, les différents bits de la clé de départ aux données.
Pour gagner en rapidité d'exécution, lorsqu'on ne passe pas de clé en paramètre à la fonction de cryptage, c'est alors la clé utilisée lors de l'appel précédent qui est utilisée. Les sous-clés sont déclarées en "static", et ne sont alors pas recalculées.

Chiffrement et déchiffrement des blocs de données

Lorsque l'on a préparé les sous-clés, on est prêt à chiffrer ou déchiffrer des blocs de données. On commence par permuter les blocs de données de 64 bits selon le tableau Des_Initial[].
        // Correspondances pour la permutation initiale des blocs
        static const int Des_Initial[64] =
        {
        58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12, 4,
        62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16, 8,
        57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11, 3,
        61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15, 7
        };
Cette permutation porte, fort à propos, le nom de permutation initiale. Elle n'améliore pas la sécurité du DES, mais elle doit être effectuée pour être conforme à la norme DES. Après la permutation initiale, le bloc de 64 bits de données est divisé en deux blocs de 32 bits, $L_0$ et $R_0$.
Après la permutation initiale le bloc de données passe par une série d'opérations répétées pendant 16 rounds. Le but de chaque round $i$ est de calculer $L_i$ et $R_i$, utilisés par le round suivant, jusqu'à obtenir finalement le bloc de données $R_{16}L_{16}$. On commence chaque round avec $L_{i-1}$ et $R_{i-1}$ et on étend $R_{i-1}$ de 32 à 48 bits à l'aide d'une fonction d'expansion, selon le tableau Des_Expansion[].
        // Correspondances pour la fonction d'expansion des blocs
        static const int Des_Expansion[48] =
        {
            32,  1,  2,  3,  4,  5,  4,  5,  6,  7,  8,  9,
            8,  9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
            16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
            24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32,  1
        };
Le but principal de cette fonction est de créer un effet d'avalanche lors du chiffrement des données : un seul bit du bloc de données affecte plus de bits à l'étape suivante, ce qui provoque donc une diffusion. Après cette étape, on calcule le OU exclusif (note $\oplus$) du résultat de 48 bits et de $K_i$, la sous-clé du round : cela donne un résultat intermédiaire de 48 bits, appelé $R_{int}$. Soit $E$, la fonction d'expansion, les opérations réalisées jusqu'à maintenant dans le round peuvent s'exprimer comme suit:

\begin{displaymath}R_{int} = E(R_{i-1}) \oplus K_i\end{displaymath}


Puis, $R{int}$ subit huit substitutions réalisées a l'aide de huit boîte-S. Chaque boîte-S j prend un bloc de 6 bits, de la position $6j$ à $6j+6$ dans $R_{int}$ et recherche une valeur de 4 bits pour lui dans la table Des_SBox[]. Cette valeur est écrite dans le tampon à la position $4j$.
        // Tableaux pour les substitutions par boîtes-S sur les blocs
        static const int Des_SBox[8][4][16] =
        {
        {
        {14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7},
        { 0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8},
        { 4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0},
        {15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13},
        },

                ...

        {
        {13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7},
        { 1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2},
        { 7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8},
        { 2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11},
        },
        };
Pour lire la table Des_SBox[], on trouve la boîte-S $j$, on recherche le numéro de ligne ayant la valeur de deux bits, formée par le premier et le dernier bit du bloc de six bits, et le numéro de colonne ayant la valeur de quatre bits formés des bits du milieu de ce même bloc (les numéros de lignes et colonnes commencent à 0). Les boîtes-S ajoutent de la confusion aux données, et font, plus que tout autre chose, la sécurité de DES : elles ont donc été longtemps l'objet d'examens minutieux.
Lorsque les substitutions par boîtes-S sont terminées, le résultat est une valeur de 32 bits que l'on permute à l'aide d'une boîte-P, selon le tableau Des_PBox[].
        // Correspondances pour la permutation-P
        static const int Des_Pbox[32] =
        {
        16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
        2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
        };
A cette étape, il est pratique de considérer les opérations du round comme une fonction $f$. Si $b_j$ est $j^e$ bloc de six bits de $R_{int}$, $S_j$ la $j^e$ boîte-S, et P la permutation-P, cette fonction se définit par :

\begin{displaymath}f = P(S_1(b_1),S_2(b_2),\cdot,S_8(b_8))\end{displaymath}


La dernière opération de chaque round consiste à calculer le OU exclusif du résultat de $f$, sur 32 bits, et du bloc gauche original passé au round, $L_{i-1}$. Lorsque cela est fait, on échange les blocs gauche et droit et on commence le round suivant. Au dernier round, cependant, on n'effectue pas cet échange. Mis ensembles, les calculs des $L_i$ et $R_i$ de chaque round peuvent être ainsi énoncés:

\begin{displaymath}L_i = R_{i-1} \\
R_i = L_{i-1} \oplus f(R_{i-1},K_1)\end{displaymath}


Lorsque les 16 rounds sont terminés, on concatène le bloc droit final, $R_{16}$, avec le bloc gauche final, $L_{16}$, pour produire le bloc de 64 bits, $R_{16}L_{16}$ (le bloc droit et le bloc gauche ne sont pas échangés dans le round final : le dernier bloc droit est donc à gauche et le dernier bloc gauche à droite). L'étape finale consiste à permuter $R_{16}L_{16}$ selon le tableau Des_Final[].
        // Correspondances pour la permutation finale des blocs
        static const int Des_Final[64] =
        {
        40,  8, 48, 16, 56, 24, 64, 32, 39,  7, 47, 15, 55, 23, 63, 31,
        38,  6, 46, 14, 54, 22, 62, 30, 37,  5, 45, 13, 53, 21, 61, 29,
        36,  4, 44, 12, 52, 20, 60, 28, 35,  3, 43, 11, 51, 19, 59, 27,
        34,  2, 42, 10, 50, 18, 58, 26, 33,  1, 41,  9, 49, 17, 57, 25
        };
Cette permutation s'appelle évidemment "permutation finale"; elle annule simplement ce que la permutation initiale avait fait plus tôt. Lorsque l'on chiffre les données, le résultat est un bloc de 64 bits de texte chiffré ; lorsque l'on déchiffre, c'est le bloc de 64 bits de texte clair.

Chiffrement par blocs

Comme nous avons vu, le DES chiffre par blocs de 64 bits. Mais dans la plupart des cas l'information à chiffrer n'est pas égale à 64 bits. Si elle est inférieure on complète de façon à aboutir à une donnée de 64 bits. Si elle est supérieure a 64 bits comme dans la plupart des cas, on découpe la donnée en bloc de 64 bits. On invoque alors le DES plusieurs fois sur chacun de ces blocs, on parle alors de mode de chiffrement par blocs.
La façon la plus simple de traiter plusieurs blocs de données consiste à ajouter chaque bloc de texte chiffré généré à ceux qui ont été générés avant lui. Cette approche primitive s'appelle ECB, ou " Electronic Code Book ". Sa simplicité la rend très populaire, mais elle est relativement peu sûre : son problème principal est que, pour une clé donnée, un bloc de texte clair sera toujours chiffré par le même bloc de texte chiffré, où qu'il apparaisse dans les données. Cela signifie que si un quelqu'un arrive à briser ne serait-ce qu'une partie des données, il peut commencer à mettre en place un décodeur pour également briser les autres parties. CBC, ou " Cipher Block Chaining " constitue une meilleure approche. C'est donc cette méthode que nous avons décidé d'utiliser.
CBC évite les problèmes de ECB en augmentant un bloc chiffré à l'aide d'opérations simples et d'une rétroaction. La rétroaction fait que chaque bloc chiffré dépend, d'une certaine façon, d'actions réalisées auparavant. Dans le mode CBC, les blocs chiffrés précédents servent à alimenter la suite, afin q'un bloc de texte clair identique ait toutes les chances d'être chiffré différemment à chaque apparition.
Pour que les blocs chiffrés précédemment puissent servir à la rétroaction, avant de chiffrer un bloc de texte clair , on fait un OU exclusif de celui-ci avec le bloc chiffré généré avant lui. Lorsque l'on déchiffre le texte, on fait un OU exclusif de chaque bloc déchiffré avec le bloc chiffré suivant. Exprimé simplement on a :

\begin{displaymath}C_i = E_K(P_i \oplus C_{i-1}\\
P_i = C_{i-1} \oplus D_K(C_i)\end{displaymath}

$C_i$ et $P_i$ et $E_K$ et $D_K$ sont, respectivement, les $i^e$ blocs de texte chiffré et clair des tampons $C$ et $P$, et $E_K$ et $D_K$ sont les opérations de chiffrement et de déchiffrement utilisant la clé $K$.

Le RSA

Principe

Comme le DES, le RSA est un chiffrement par bloc, mais la taille du bloc varie selon celle des clés. Dans YooGoo nous utilisons des clés de 256 bits, ce qui nous permet dans le cas d'un triple-DES d'envoyer 3 clés DES ($3*64 < 256$).
RSA est considéré très sûr, mais il est considérablement plus lent que DES. Comme pour ce dernier, la sécurité du RSA n'a jamais été prouvée, mais elle est liée au problème difficile de factoriser des grands nombres (des nombres contenant au moins 200 chiffres). Comme on ne connaît aucune solution efficace à ce problème, on suppose qu'il n'existe pas de moyen efficace de briser RSA.
RSA est fondé sur des principes moins obscurs que les permutations numériques et les substitutions utilisées par le DES. Le chiffrement et le déchiffrement des données dépendent d'une exponentiation modulaire, une opération de l'arithmétique des modulos.

Calcul des clés publiques et privées

Avec RSA, la clé publique et la clé privée fonctionnent ensemble comme une paire. La première sert à chiffrer un bloc de données, après quoi seule la clé privée correspondante peut permettre de le déchiffrer. Lorsque l'on génère les clés, on suit plusieurs étapes afin d'assurer que ce mariage fonctionne. Ces étapes vérifient également qu'il n'y a pas moyen de déterminer une des clés à partir de l'autre.
Pour commencer, on choisit deux grands nombres premiers, appelés $p$ et $q$. Etant donné les techniques de factorisation actuelles, ces nombres doivent posséder au moins 200 chiffres pour être considérés comme sûrs. Puis, on calcule $n$, le produit de ces nombres :

\begin{displaymath}n = pq\end{displaymath}

On choisit alors un petit entier impair, $e$, qui fera partie de la clé publique. Le critère le plus important dans le choix de $e$ est qu'il ne doit pas avoir de facteur commun avec $(p - 1)(q -
1)$ : en d'autres termes, $e$ et $(p - 1)(q -
1)$ sont premiers entre eux. Nous utilisons 17, car c'est un nombre premier, nous sommes alors sûr qu'il n'est pas de facteur commun. L'utilisation d'une valeur précise pour $e$ ne compromet pas la sécurité de RSA car le déchiffrement des données est fonction de la clé privée.
Ensuite, on calcule une valeur correspondante $d$ qui fera partie de la clé privée. Pour cela, on calcule l'inverse de $e$, modulo $(p - 1)(q -
1)$, de la façon suivante :

\begin{displaymath}d = e^{-1} mod(p - 1)(q - 1)\end{displaymath}

Maintenant que nous avons des valeurs pour $e$ et $d$, on publie $(e,n)$ comme étant la clé publique $P$ et on garde $(d,n)$ secret comme clé privée $S$ :

\begin{displaymath}P = (e,n)\\ S = (d,n)\end{displaymath}

Ceux qui chiffrent les données utilisent $P$ et ceux qui déchiffrent, $S$. Pour s'assurer que quelqu'un connaissant $P$ ne puisse calculer $S$, les valeurs utilisées pour $p$ et $q$ ne doivent jamais être révélées.
La sécurité offerte par le couple $P$ et $S$ vient du fait que la multiplication est une fonction à sens unique, ce qui est fondamental en cryptographie. Exprimé simplement, une fonction à sens unique est une fonction relativement simple à calculer dans un sens, mais impossible à trouver dans l'autre. Dans RSA, par exemple, la multiplication de $p$ et $q$ est facile, mais la factorisation de $n$ en $p$ et $q$ est extrêmement lente si les valeurs choisis pour $p$ et $q$ sont suffisamment grandes.

Chiffrement et déchiffrement des blocs de données

Pour chiffrer et déchiffrer des données avec RSA, il faut d'abord choisir une taille de bloc en s'assurant que la plus grande taille que pourra contenir ce bloc sera inférieure à $n$. Si, par exemple, $p$ et $q$ sont des nombres premiers de 200 chiffres, n fera à peine moins de 400 chiffres. On doit donc choisir une taille de bloc suffisamment petite pour ne stocker que les nombres ayant moins de chiffres que cela. En pratique, on prend souvent une taille de bloc d'un nombre de bits égal à la plus grande puissance de 2 inférieure à $n$. Si $n = 209$, par exemple, on choisirait une taille de bloc de 7 bits car $2^7 = 128$ est inférieur à 209 et $2^8 = 256$ est supérieur.
Pour chiffrer un bloc de texte clair $M_i$, le ième bloc de données d'un tampon $M$, on utilise la clé publique $(e,n)$ pour prendre la valeur numérique de $M_i$, l'élever à la puissance $e$, et prendre le résultat modulo $n$. Cela donne un bloc de texte chiffré $C_i$. Le modulo $n$ garantit que $C_i$ tiendra dans la même taille de bloc que celle du texte clair. Ainsi, pour chiffrer un bloc de texte clair, on a :

\begin{displaymath}C_i = M_i^e mod n \end{displaymath}

Pour obtenir de nouveau le texte clair $M_i$ à partir de $C_i$, ième bloc de texte chiffré d'un tampon $C$, on utilise la clé privée $(d,n)$ pour prendre la valeur numérique de $C_i$, l'élever à la puissance $d$ et prendre le résultat modulo $n$. Ainsi pour déchiffrer un bloc de texte chiffré, on a :

\begin{displaymath}M_i = C_i^e mod n\end{displaymath}

Nombres infinis

Comme nous l'avons vu, RSA est sûr que si l'on travaille sur des nombres très grands (200 chiffres au moins). Il faut alors créer une classe de nombres infinis qui permet de réaliser toutes les opérations classiques (addition, soustraction, division, multiplication, modulo, exponentielle).
La première méthode qui a été réalisée est d'utilisé des chaînes de caractères pour stocker les nombres. Cette méthode permet d'afficher et de saisir des nombres très facilement. Mais que très peu de caractères sont utilisés ('0'-'9') et on gâche alors beaucoup d'espace. Les opérations sont effectuées comme si on les faisaient à la main, c'est à dire que pour chaque chiffre on effectue l'opération et on garde une éventuelle retenue pour l'inclure dans le calcul du chiffre suivant. La classe ainsi réalisée marche très bien mais est malheureusement très lente.
Nous avons alors décidé de reprendre une classe déjà réalisée, qui reprend un peu la même méthode mais au lieu d'utiliser les caractères '0'-'9', utilise des unsigned long int. On met alors côte à côte tous ces nombres et on obtient alors un nombre de la taille que l'on veut (dans notre cas 7). Le calcul des opérations est plus rapide car on calcul alors par paquet de 32 bits. Il suffit alors comme précédemment de garder la retenue à chaque fois.

Génération de nombres infinis

Les nombres $p$ et $q$ doivent être premiers. Pour pouvoir générer une clé aléatoirement il faut donc pouvoir générer un nombre premier aléatoirement. La méthode la plus évidente serait de générer un nombre quelconque et puis de tester s'il n'est pas multiple d'un nombre premier inférieur ou égal à sa racine carré. Cette méthode est très lente surtout lorsqu'on travaille sur des grands nombres, de plus il faut avoir précédemment calculé tous les nombres premiers plus petits que le nombre aléatoire. C'est quand même la seule méthode sûr à 100%.
Mais pour accélérer le test, on à mis au point des méthodes probabilistes qui sont fiables. La méthode de Rabin-Miller est considérée actuellement comme la plus efficace. Il faut l'effectuer 4 fois si on veut avoir une réponse quasiment exacte.
Le test de Miller-Rabin prend en entrée un entier impair $n > 1$ à tester. Il renvoie en sortie FAUX ou VRAI.
  1. Calculer $b$$b$ est le nombre de fois que 2 divise $n - 1$
  2. Poser $2^b * r = n - 1$$r$ est un entier impair.
  3. (A répéter 4 fois)
                A = rand(n-1)       // 1 < a < n-1
                y = a^r mod n
                Si ( (y != 1) et (y != n - 1) ) alors
                    j := 1
                    Tant que ( (j < b) et (y != n - 1) ) faire
                        y := y^2 mod n
                        Si (y = 1) alors retourne (FAUX)
                        j := j + 1
                        Si (y != n - 1) alors retourne (FAUX)
                    Fin fant que
                Sinon retourne  (VRAI)
    

La procédure de connexion

Lors de la connexion d'un client au serveur, il faut échanger la clé DES afin que le client et le serveur puissent par la suite communiquer. Cette fonction est lancée dès que le serveur reçoit une connexion TCP/IP. Si toute la procédure se déroule bien l'utilisateur sera connecté au serveur et pourra alors interagir avec lui. En cas de mauvais fonctionnement il sera déconnecté. La fonction n'effectue pas les mêmes opérations sur le serveur et sur le client, elles dépendent l'une de l'autre. Mais dans les deux cas, la fonction renvoie la clé DES, et NULL si la fonction s'est mal déroulé. Les différentes étapes de la connexion sont :
  1. Le serveur envoie la clé RSA publique en clair au client. Les clés RSA sont générées au lancement du serveur.
  2. Le client reçoit la clé publique. Il génère une clé DES et la crypte avec la clé RSA publique du serveur. Il envoie le message crypté au serveur.
  3. Le serveur reçoit le message crypté du client. Il le décrypte avec sa clé RSA privée. Il obtient alors la clé DES du client en clair.
  4. On effectue ensuite un test pour voir si la clé est bien la même sur le client et le serveur. Le client envoie un message test crypté, "ceci est un message test", au serveur. Le serveur reçoit le message crypté et le décrypte avec la clé DES qu'il a reçu précédemment. Si le message correspond bien le client est connecté, sinon il est rejeté avec comme erreur ERR_BADKEY.

La couche réseau: Winsock

Récapitulatif

Comme nous l'avons vu dans le cahier des charges, le serveur devra gérer toutes les connections des utilisateurs ainsi que leurs différentes actions. Nous espérons qu'il supportera un bon millier de connections. Mais pour l'instant il nous est difficile de prévoir le nombre exact de connections possibles. Le serveur fonctionnera sur le protocole TCP/IP et utilisera la technologie des sockets (WinSock pour la version Windows, la version Unix n'étant pas prévue par le cahier de charges).

Stratégie d'entrées/sorties :

La stratégie d'entrées/sorties est la manière dont les informations reçus et envoyées seront traitées. Un bon choix est déterminant car tout le code réseau repose sur celui ci. Pour rappel les différentes méthodes possibles sont :
Sockets Bloquants
: Par défaut, un socket est bloquant, c'est à dire qu'il ne rend pas la main à l'application tant qu'il n'as pas finis d'effectuer ces tâches ou qu'il y a eu un problème.
Sockets purement non-bloquants
: Un appel avec un socket non-bloquant rend la main immédiatement si il ne réussit pas à terminer sa tâche immédiatement. Ceci permet au programme d'effectuer d'autres tâches pendant que les opérations du réseau finissent. Par contre il faut continuellement tester le socket pour savoir si son opération est finie.
Sockets Asynchrones
: Ce sont des sockets non-bloquants qui renvoient automatiquement un message quand il se passe quelque chose d'intéressant sur le socket.
Select()
: La fonction select() permet à un thread de s'occuper d'un groupe de sockets intéressants, c'est à dire qui reçoivent ou émettent des données. Elle est généralement utilisée pour éviter d'effectuer des test continus sur les sockets non-bloquants.
Objets événement
: utilisés avec WSAEventSelect(), ce mécanisme rassemble à la fonction select(), mais un peu plus efficace. Par contre elle ne fonctionne que sous Windows, tandis que select() fonctionne aussi avec les sockets BSD.
Overlapped I/O
: une des nouvelles fonctions de Winsock 2. C'est la méthode la plus efficace car elle se base directement sur la méthode de Windows pour gérer les entrées/sorties. Malheureusement cette technique n'est utilisable que sous Win32.
Si on dresse un tableau récapitulatif des différentes méthodes utilisables pour chaque système d'exploitation on obtient :

Win9x WinCE Win NT4+ Win NT 3.x Win16 Unix
Sockets Bloquants yes yes yes yes yes yes
Sockets non-bloquants yes yes yes yes yes yes
Sockets asynchrones yes no yes yes yes no
Objects événement yes no yes no no no
Overlapped I/O yes no yes no no no
Threads yes yes yes yes no yes


On retrouve alors le choix qui a été fait des le cahier des charges, de faire un serveur multi-thread couplé avec des sockets bloquants. Cette solution est de loin celle qui représente le meilleur rapport entre rapidité et portabilité.

Fonctionnement de Winsock

Winsock se présente sous forme d'une dll, il a donc fallu apprendre a insérer une dll dans un projet Visual Studio. En effet, ceci ne se présente pas sous la même forme que sous Delphi ou il suffit d'inclure le .h, il faut utiliser inclure au projet un .lib et le .h correspondant. De plus la librairie Winsock doit être initialisé, ceci se fait par l'appel de la fonction WSAStartup() tandis que la fermeture se faite par WSACleanup() (il est à noter que lors de la fermeture des connections et de la librairie il faut vérifier s'il y a ou nom des messages en attente). Une fois ces opérations réglées on peut accéder à toutes les fonctions externes de la librairies : celles qui sont déclarées dans Winsock.h.
Le serveur commence par initialiser un socket en mode Listen. Ce socket sert à recevoir les connections entrantes. Pour initialiser un socket on passe par une classe sockaddr_in qui sert a décrire le socket. La classe sockaddr_in est en fait une classe enfant de sockaddr car il existe en fait une classe héritée pour chaque type de protocole de connexion (dans notres cas c'est pour le protocole TCP/IP). On a alors :
            sockaddr_in sinInterface;
            sinInterface.sin_family = AF_INET;
            sinInterface.sin_addr.s_addr = nInterfaceAddr;
            sinInterface.sin_port = Port;
nInterfaceAddr est l'IP de l'interface sur laquelle on désire écouter les connections, celle ci a été précédemment obtenue grâce à la fonction de conversion de Winsock : inet_addr() à partir d'une adresse de la forme x.x.x.x. Ensuite on affecte ensuite cette description au socket grâce à la fonction bind(). Enfin on met le socket en écoute avec listen().
Le serveur continue alors d'écouter jusqu'à ce qu'on le ferme. Pour chaque connection entrante il va recevoir les coordonnées du client et lancer un nouvelle thread qui va s'occuper de gérer le client qui s'est connecté. Lorsqu'il y a du mouvement sur le socket en écoute, celui reçoit les coordonnées du client grâce à la fonction accept(). Le lancement de la nouvelle thread se fait grâce à CreateThread() auquel on passe le socket contenant les informations du client avec qui on communique.
Il est important de noter que toutes ces fonctions ont une syntaxe très proche de la version sous Unix des socket, ainsi que la création de thread qui est à peu de choses près pareil. De plus les fonctions utilisant Winsock ont toutes été regroupées dans un même fichier afin de faciliter le portage du code sous une autre plateforme.
La thread principale qui gère les connections ne peut communiquer qu'avec un seul utilisateur en même temps. C'est à la fois une bonne et un mauvaise chose. Une bonne chose car tout ce qui est envoyé et reçus dans ce thread vient ou provient de la même personne. Par contre dès que l'on à besoin d'envoyer un message à quelqu'un d'autre il faut passer par des variables globales. Il faut alors faire attention à la gestion de la mémoire car il faut interdire à deux threads de travailler sur un même objet en même temps. Ceci sera l'objet de notre travaille dans la réalisation des fonctions du protocole et sera donc traité à la deuxième soutenance. Néanmoins la méthode pour s'échanger des informations a déjà été mise au point, on se servira d'une file de message appartenant à la classe user (pour plus de détails sur celle ci se référer à la section qui lui est dédiée).
Pour ce qui est de l'envoie et la réception des données on utilise les fonctions recv() et send(). Lorsqu'on envoie un message, on boucle jusqu'à ce qu'on soit sur que tout les octets soient envoyés. Lors de la réception, cette méthode qui permet d'être sûr d'avoir envoyé tout le message ne peut pas être faite car on ne connaît pas à l'avance la longueur du message que l'on reçoit. C'est lors des procédure d'envoie et de réception que le cryptage des messages est effectués (voir la partie sécurité).

Gestion des erreurs

La plus grosse partie du serveur consiste à bien gérer les erreurs. Il faut tester la valeur de retour de la plus pars des fonctions pour voir si tout s'est bien déroulé. Ceci est crucial dans un serveur car un plantage pourrait avoir un effet désastreux. A chaque fois qu'il se produit une erreur il faut la conserver dans un fichier de log, et faire en sorte que le serveur continue ses tâches comme si de rien était. Pour ce qui est de la gestion des logs, celle ci n'est pas encore implémentée, pour l'instant le serveur se limite à afficher à l'écran les erreurs, elle sera implémentée plus tard, avec les statistiques du serveur.
Mais tout n'est pas si simple car la plupart des fonctions Winsock ne renvoient pas directement les erreurs, mais celle si sont accessibles à travers la fonction WSAGetLastError(). Malheureusement cette fonction retourne des nombres comme erreurs et ceux ci sont peu explicites et non pratique à utiliser dans des logs. Il a donc été réalisé une fonction permettant de transformer ce numéro en message d'erreur afin d'avoir un affichage plus correct et une utilisation plus propre.

Le protocole

But d'un protocole

Le protocole est le langage qui permet à deux applications réseau de communiquer. Nous avons donc écrit un protocole de communication YooGoo. Si une application respecte le protocole, elle est en mesure de communiquer soit avec le client, soit avec le serveur de YooGoo. De plus, le protocole nous permet de coder le serveur et le client indépendamment l'un de l'autre. Il suffit qu'il respecte tous les deux le protocole pour qu'ils soient compatibles. Lors de la conception du protocole, nous avons fait bien attention à ce que celui-ci soit "logique". Il ne faut pas qu'il y ait de fonctions incompatibles, ni de fonction double. On doit aussi penser comment faire passer certaines informations entre les clients, etc. Dans un protocole tel que le FTP et HTTP, il n'y a pas besoin de faire passer de l'information entre les clients. Chaque connexion au serveur est totalement indépendante.

Conception du protocole

Tout d'abord, YooGoo est crypté. Toute la première phase de la connexion se compose de la génération et de l'échange des clés de cryptage. Dans la suite, le cryptage est totalement transparent. Lorsque nous appelons la fonction permettant l'envoie de donnée, celle-ci crypte les données avant de les envoyer. Comme YooGoo ressemble pour la plupart de ses fonctionnalités à l'IRC, nous nous sommes beaucoup inspiré du protocole de l'IRC (cf. RFC 1412??? disponible sur www.YooGoo.com).
Pour chaque fonction un code d'erreur est renvoyé au client. La valeur 00 signifie que tout s'est bien passé. Tous les codes < 100 signifient que ce ne sont pas des erreurs fatales. Les erreurs comprises entre 400 et 499 signifient que l'erreur est fatale et que la fonction s'est terminée anormalement. Ces codes d'erreur sont important car ils seront aussi utilisés en interne dans le serveur. Néanmoins, nous avons décidé de ne pas renvoyer d'erreur de la part du client. Effectivement, nous pensons qu'il n'est pas utile au serveur de savoir si la donnée est bien reconnue (il ne peut rien y faire s'il y a une erreur...). De plus, les messages envoyés par le serveur sont souvent des messages d'informations, il y a donc que très peu d'erreur possible. Je rappelle que TCP/IP possède un code de correction d'erreur et qu'une donnée arrive forcement à destination sans erreurs.
Pour une description détaille de toutes les fonctions du protocole, je vous invite à vous reporter en annexe A.

Gestion du serveur

La classe user

Les droits

Le principe des droits est très simple, chaque utilisateur donne un niveau de droit à chacune des personnes qu'il désire. Un droit différent de 1 donne le permet de figurer sur la contact list. Le droit 0 banni l'utilisateur concerné qui figure sur la contact list en tant que banni. Le droit de 1 est attribué à toutes les personnes de la communauté YooGoo ne figurant pas sur la contact list. Enfin les droits supérieurs à 1 donne une importance différente aux personnes de la contact list, qui pourront accéder à certains champs de votre profil grâce à leur niveau de droit.
Donc chaque champ du profil contiendra un niveau de droit. Les champs de recherche comme le pseudo auront un niveau fixe de 1, afin d'être vu par toute la communauté hormis les bannis.

Introduction

La classe User à pour but de gérer tout ce qui touche à l'utilisateur. C'est-à-dire qu'elle contient toutes les fonctions ayant rapport au profil, à la contact list, à la file des messages. Elle est composée de fonctions publiques qui seront appelées par le programme, et de fonctions privées qui seront cachées du reste du programme mais appelées en interne à la classe. Ainsi chaque utilisateur en ligne sera un objet de cette classe. Par ailleurs la classe User possède un compteur permettant de savoir le nombre d'utilisateurs chargés en mémoire, ce qui nous permettra d'effectuer des statistiques. Ce compteur est réalisé grâce à une variable static à la classe, elle est donc indépendante de chacun des objets. Cette variable est incrémentée dans le(s) constructeur(s) de la classe. Et pour nous permettre de récupérer cette valeur, il faut appeler la fonction user::getnbuser dans le programme. Cette fonction est également static à la classe.

Type User

Chaque objet de la classe sera chargé en mémoire. Il faut donc alléger au maximum la structure de l'objet user. Or l'élément prenant le plus de place est bien évidemment le profil. Il n'a donc fallu garder que les éléments indispensables à un fonctionnement rapide du programme. Le type User se décompose en trois structures, la structure profil, la structure info et une structure dédiée à la file de messages. La structure profil contient les critères de recherches (nick, sexe, ville, date de naissance) mais également le mot de passe et deux 'pointeurs' vers les fichiers Profil et Contact désignant un numéro de ligne. La structure info contient elle des informations temporaires utiles pour la procédure de la thread, telles que l'adresse IP, le port, la clé DES, (le statut). Enfin la structure file de messages est composée d'un tableau de char et d'un pointeur vers un autre message.

Profil

Il existe donc deux profils. Un profil lite, le plus petit possible, destiné à la mémoire principale et un profil complet destiné à la mémoire secondaire, regroupant toutes les infos disponibles sur un utilisateur. Les informations sont celles qu'on trouve régulièrement sur les chats (ICQ, Caramail, IRC ...). Le profil complet regroupe les champs du profil lite, plus des champs complémentaires tels que le Password, le nom, le prénom, l'adresse, le code postal, la langue, le pays, le numéro de téléphone, l'adresse mail, un " pointeur " vers le numéro de ligne dans le fichier contact, une chaîne contenant le chemin vers une image, et les intérêts. De plus chaque champ possède un niveau de droit qui sera le premier caractère de chaque champ (ex : 4Dupond, seuls les personnes ayant un niveau supérieur à 3 sur la contact list de monsieur Dupond pourront voir ce champ).

Fichier profil.yoo

Afin de pouvoir conserver tous les profils après une extinction du serveur ou une panne éventuelle, il faut que tous les profils soient stockés dans un fichier : le fichier profil.yoo. Ce fichier est d'autre part indispensable car tous les profils complets des utilisateurs ne pourront pas être stockés dans la mémoire vive. De plus afin d'avoir une vue sur l'ensemble des profils, il a été décidé d'en faire un fichier ascii et non binaire. Ce choix nous permettra de visionner les profils et éventuellement de corriger, supprimer, ajouter des profils à notre guise, à l'aide d'un éditeur de texte classique. Par ailleurs le fichier sera formaté, c'est-à-dire que chaque champ du profil aura une colonne de taille fixe pour tous les utilisateurs, ce qui permettra d'avoir une meilleure vision de notre fichier. Enfin chaque profil occupera une ligne dans le fichier où chaque champ sera délimité par un caractère spécial qu'il sera possible de changer à tout moment. Pour l'instant le caractère délimiteur est le " $\vert$ ".
Ce fichier devra être compatible avec notre procédure d'ajout, ou plutôt nous allons adapter notre procédure d'ajout à notre vision du fichier. Le format du fichier devra donc faciliter la construction de la procédure d'ajout. Pour cela chaque ligne aura le même nombre de caractères. Il sera ainsi plus aisé de se déplacer directement à une ligne, il suffira d'utiliser la fonction fseek, qui prend en paramètre un pointeur sur FILE, le numéro du caractère voulu, et l'origine (début, fin, ou position actuel du pointeur), en multipliant le numéro de la ligne désirée par le nombre de caractères par ligne.
Les fonctions publiques associées au fichier profil.yoo sont au nombre de 3. La première est celle d'ajout, elle prend en paramètre une chaîne de caractères contenant le profil complet. Cette chaîne est dans un premier temps analysée, c'est-à-dire qu'on vérifie si son formatage est correct, si les champs numériques ne contiennent pas de lettres, et si la date de naissance est cohérente. Le formatage de cette chaîne est possible grâce une nouvelle fois à un caractère délimiteur. Cette chaîne peut par exemple peut passer le test sans problème :
    "2!19821203!City!FirstName!Name!PassWord!address!zipcode!
    10!10!numtel1!numtel2!email1!email2!photo.jpg!interests!".
Une fois analysée, la chaîne est stockée dans le fichier. Pour cela, il faut ouvrir le fichier à l'aide de la fonction fopen() qui retourne un pointeur sur FILE. En ouvrant un fichier il faut choisir un mode dans notre cas le mode append est le plus approprié. Ensuite la chaîne est écrite caractère par caractère juste qu'à la fin du champs, qui sera complété par des espaces jusqu'au prochain champ. Le nombre d'espace dépend bien sûr de la taille du champ. Une fois l'écriture terminée il faut refermer le fichier à l'aide de la fonction fclose().
La seconde fonction est celle de modification de champ. Elle prend en paramètre le nouveau champ (chaîne de caractères) ainsi que la désignation du champ établie par une série de constantes (ex : MOD_NICK pour modifier le pseudo). Elle fonctionne sur le même principe que la fonction de sauvegarde pour ce qui est de la manipulation du fichier (fopen(), fclose() ...), sauf que le mode n'est plus append mais emphread /write, car il faut trouver le champ désiré (donc lire) et le modifier (donc écrire).
La dernière fonction permet de récupérer le profil d'une personne si nous en avons l'autorisation. Cette fonction est appelée avec un pointeur sur char qui contiendra le profil de retour, et l'utilisateur voulu (sous le type user). Ce qui implique qu'il sera impossible de visionner le profil d'une personne déconnectée. Dans un premier temps, il faut aller rechercher les droits de l'utilisateur demandeur dans la contact list. Si l'utilisateur est banni on retourne un message d'avertissement, s'il n'existe pas on lui donne un droit de 1. Ensuite on se positionne sur la ligne contenant le profil grâce à la variable numline faisant partie du profil lite. La ligne est parcourue à l'aide de la fonction fseek() qui déplace le pointeur du fichier sur le premier caractère de chaque champ. Ainsi il est plus aisé de récupérer les champs qui sont autorisés pour l'utilisateur. Les champs récupérés sont ajoutés à la chaîne de retour.

Contact List

La Contact List a pour but de faciliter la vie du chatteur. En effet grâce à cette dernière il peut voir automatiquement les membres de la communauté YooGoo avec lesquels il parle fréquemment. Dans sa conception la Contact List n'est rien d'autre qu'une simple liste associant un niveau de droit, donc un numéro, à une personne. Ainsi la liste des bannis est intégrée à la contact list. De plus avec YooGoo c'est le serveur qui hébergera la contact list. Ceci permettra même après un formatage du disque du côté client de pouvoir récupérer sa contact list, dès la reconnexion au serveur. C'est d'ailleurs la solution que vient d'adopter ICQ dans sa dernière version (ICQ2001b). Le serveur se contente juste de garder les noms, et le client YooGoo s'occupera de la personnaliser : trie, couleur ... Ce choix sera bien sûr plus délicat à traiter, et ralentira bien évidemment le serveur à cause des accès au fichier et aux tests fréquents, mais sa praticité prime sur le reste. Ainsi la contact list sera modifiée par le client à travers des appels de fonction du serveur.

Fichier contact.yoo

Le même problème que pour les profils se pose à la contact list. Il faut pouvoir stocker toutes les contact lists dans un fichier. Un problème majeur qui n'apparaît pas avec les profils est que une liste de contact n'a pas la même longueur selon l'utilisateur. Elle peut être vide, ou regrouper tous les utilisateurs de la communauté. Pour remédier à se problème la structure du fichier à été repensée. Chaque ligne correspond à un utilisateur, et ne contient que 5 contacts. La structure est la suivante :
ProchaineLigne|Propriétaire|Contact1|Contact2|Contact3|Contact4|Contact5|
Ainsi lorsqu'on ajoute un contact il est ajouté à la ligne, et s'il n'y a plus de place, on ajoute une nouvelle ligne au fichier en modifiant l'en-tête de la ligne précédente. Un utilisateur possède donc (nombre d'utilisateur / 5) + 1 ligne(s) dans le fichier. De même que pour le profil, 4 fonctions publiques agissent sur la modification du fichier contact.yoo.
Add_contact (user, short)
:
Le premier paramètre est l'utilisateur à ajouter, le second est le droit qu'on lui attribue.
Avant d'ajouter on effectue quelques tests. On vérifie que l'utilisateur envoyé n'est pas celui du propriétaire car on ne peut pas s'ajouter dans sa liste, que l'utilisateur n'existe pas déjà dans la liste (à l'aide de la fonction find_contact). Dans les deux cas on renvoie un code erreur.
Comme on ne peut pas ajouter n'importe qui dans une contact list, il faut envoyer un message request à l'utilisateur concerné pour obtenir son accord. Cet utilisateur doit alors répondre par oui ou non. Dans le cas d'un oui on ajoute un champ dans les deux contact list. Il existe un cas à par, celui du banni. Lorsqu'on désire bannir une personne (droit 0), on envoie juste un message texte " Vous avez été banni par ... " et on écrit dans les deux listes sans request.
Rmv_contact (char*)
:
Le paramètre à envoyer est le nom de l'utilisateur à supprimer. Et comme lorsqu'on supprime dans une liste on doit supprimer dans la liste de la personne en question, la fonction remove() enfile un message texte destiné à la personne supprimée " Vous avez été supprimé de la Contact List de ... ", et un message appelant la fonction remove() chez l'autre personne afin de bien supprimer des deux côtés.
Du point de vue du fichier on doit rechercher le pseudo, s'il n'existe pas on renvoie un code erreur sinon on le remplace par des espaces.
Find_Contact (char*)
:
Le paramètre à donner est le pseudo recherché. La fonction doit dans un premier temps se positionner sur le numéro de la première ligne de la Contact List dans le fichier contact.yoo. Puis elle charge la ligne dans un buffer (la fin de ligne seulement, où se trouvent les pseudos), afin de faciliter la recherche. Si le pseudo à été trouvé on retourne son droit sinon on retourne le droit standard, c'est-à-dire 1.
Chg_right (char*, int)
:
Le premier paramètre doit être le pseudo de l'utilisateur à modifier. Le second est celui du nouveau droit de cet utilisateur. Le principe de cette fonction est très simple, elle appelle la fonction Find_Contact() afin de retrouver la position du pseudo. S'il a été trouvé on modifie son droit sinon on retourne un message d'erreur.

File des messages

But

La file des messages a pour but de stocker tous les messages de l'utilisateur concerné. Tous ces messages peuvent être des messages texte destinés à être envoyé à d'autre utilisateur de la communauté YooGoo ou tout simplement des appels de fonctions. Par exemple lors d'un ajout d'utilisateur dans la Contact List, on empile un message qui contiendra le message request qui appel une fonction au niveau du client.

Fonctionnement

La file est composée d'une chaîne d'une longueur de 1024 caractères contenant le message et d'un pointeur vers une autre structure message. Cette file est donc une file classique comme celles vues en cours. Dans sa construction la file possède une tête, et une queue déclarées en privée. Ces variables ne peuvent donc pas être modifiées accidentellement par du code extérieur à la classe. La file des messages est gérée par 3 fonctions publiques :
enfile(char*)
:
Cette fonction enfile un message. Le message à enfiler est envoyé avec un pointeur sur char qui est recopié dans le message de la file à l'aide de la fonction strcpy(). On alloue avec new (équivalent du malloc() en C++), on préserve la tête et on fait la mise à jour des pointeurs.
defile(char*)
:
Cette fonction défile un message, si la file n'est pas vide. On défile par la queue. A chaque défilement on supprime de la mémoire une structure de la file avec l'instruction delete().
est_vide()
:
Cette fonction compare juste la tête avec NULL. Si le test est vrai alors la file est vide sinon elle possède au moins un élément.

La classe canal

Introduction

La classe canal ressemble de part sa structure à la classe User. Les principes de fonctionnement sont proches mais pas rigoureusement les mêmes. La Contact List de la classe User peut ainsi se rapprocher de la liste des utilisateurs de la classe canal. Cependant le principe de fonctionnement n'est pas le même c'est pourquoi nous devons l'expliquer.

Principe

Les canaux ou salons permettront aux utilisateurs de pouvoirs parler tous en même temps dans des sections à thèmes. Il existera des canaux permanents qui ne pourront donc pas être effacé du serveur. De plus les utilisateurs auront la possibilité d'en créer. Pour créer un canal il suffit d'appeler la fonction joinable. Si le canal existe l'utilisateur tente de se connecter au canal demandé sinon un canal est créé. Ce canal comportera seulement un nom et un mot de passe. Ce sera le créateur qui devra personnaliser son canal avec les fonctions de modification. Il aura alors le choix entre un canal public et un canal privé. Les canaux privés ne sont que des canaux publics dont l'accès nécessite un mot de passe. Chaque canal sera chargé en mémoire. Tout comme avec le type user, le type canal devra être assez léger pour ne pas occuper trop de place en mémoire. De plus chaque canal devra posséder la liste des utilisateurs connectés, des utilisateurs bannis, des modérateurs, et des chanroots. Ils seront stockés sous forme de liste chaînée. Les modérateurs sont des utilisateurs à pouvoir. C'est-à-dire qu'ils peuvent bannir des personnes, les kicker, tout cela en fonction des droits qui leurs sont attribués. Les modérateurs d'un même canal ont tous les mêmes droits. Ce sont les chanroots qui distribuent les droits. Ils sont modifiables à tout moment. Le chanroot est un modérateur qui possède tous les droits. De plus un chanroot peut ajouter, mais aussi supprimer un chanroot.
Afin de conserver les canaux permanents, ils seront stockés dans un fichier à l'extinction du serveur; on y stocke les infos du canal (mot de passe, nom, ...), les utilisateurs particuliers (chanroots, bannis, modérateurs).
D'un point de vu de la gestion " interne " au serveur, une seule thread gérera tous les canaux. De plus contrairement à la classe user, la file des messages sera commune à la classe et non pas à chaque canal.

Type classe

Notre type classe sera composé de 6 champs qui seront gardés en mémoire.
  1. name : char[20] définissant le nom du canal
  2. cat : int définissant le thème ou catégorie du canal (sport, cinéma ...)
  3. pass : char[8] définissant le mot de passe. S'il existe le canal est considéré comme privé
  4. description : char[50] donnant une description sommaire du contenu du canal

File des messages

La file des messages de la classe Canal est la même que celle de la classe User à une exception près. La file des messages des canaux est unique, c'est-à-dire que tous les messages enfilés pas les canaux se retrouvent dans une seule file qui ne dépend pas de l'objet canal. Pour pouvoir réaliser une telle file il suffit de passer la tête de la file en variable statique à la classe. La tête étant la même pour tous les canaux ils enfilent ainsi tous au même endroit.
La déclaration de la variable est la suivante :
        static Tcanal *tete;
Et lorsqu'on définit une variable statique dans une classe il faut l'initialiser ainsi :
    canal::Tcanal * canal::tete = NULL;

Principe des listes

Pour pouvoir fonctionner correctement la classe canal a besoin de listes. Elles sont au nombre de quatre, toutes basées sur la même structure Tlist. Cette liste est doublement chaînée et permettra de faire une recherche par dichotomie dans la liste des connectés. Il y a une liste pour les chanroots, une pour les modérateurs, une autre pour les bannis, et une dernière pour les utilisateurs connectés. Le but de faire 4 listes est de simplifier l'écriture dans un fichier des canaux permanents, il suffira d'écrire les trois premières listes.
Elles possèdent une tête et une queue. Lors de la création, tête et queue pointe sur NULL. Puis on distingue différents cas pour l'insertion et la suppression : pour la tête et la queue. En effet selon qu'on insert en tête ou en queue la mise à jour des pointeurs se fait différemment.

Constructeur et destructeur

Pour pouvoir créer et détruire proprement un canal il faut adapter le constructeur et le destructeur à nos besoins.
Constructeur :
canal::canal();
Ce constructeur est le constructeur par défaut. Il existe trois sortes de constructeurs, le constructeur par défaut qui ne prend aucun paramètre, le constructeur de copie qui prend un certain nombre de paramètres servant à initialiser l'objet, et le constructeur par référence qui permet de copier des structures plus complexes impliquant des pointeurs. Notre constructeur initialise tout les champs à 0, vide les chaînes et fait pointer les pointeurs vers NULL. De plus il incrémente la variable statistiques nbcanal, désignant le nombre de canaux créés.
Destructeur :
canal:: canal();
Le destructeur a pour but de détruire proprement l'objet. Notre destructeur vide dans un premier temps toutes les listes par l'appel d'une fonction privée parcourant les listes et supprimant les entrées. Enfin on décrémente la variable statistique nbcanal.

Gestion des utilisateurs

Pour gérer les utilisateurs on aura besoin principalement de deux fonctions qui porteront sur la liste des utilisateurs.
Fonction join :
int canal::join(char nuser[20], char pass[8]);
La fonction join permet à un utilisateur de pouvoir se connecter à un canal désiré. Le premier champ désigne le nom de l'utilisateur voulu, et le deuxième champ désigne un mot de passe facultatif. Le mot de passe permet de rejoindre un canal privé. La fonction join ne fait qu'ajouter une entrée dans la liste des utilisateurs connectés, mais cette entrée est ajoutée de telle sorte que la liste soit triée dans l'ordre alphabétique.
Fonction part :
int canal::part(char nuser[20]);
La fonction part permet à un utilisateur de se déconnecter proprement d'un canal. Elle ne contient qu'un paramètre celui de la personne à déconnecter. Cette fonction ne fait que supprimer une entrée dans la liste des connectés.
Fonction sendmsg :
int canal::sendmsg(char message []);
La fonction sendmsg peut être appelé par n'importe qu'elle utilisateur connecté au canal. Cette fonction est relativement simple, elle enfile le message passé dans le premier paramètre dans la file du canal ou plutôt de la classe canal étant donné que la file est commune. Ce sera la fonction la plus appelée dans le canal.

Gestion des modérateurs

Voici les fonctions qui permettent de créer des modérateurs, mais également les fonctions qu'ils devraient pouvoir utiliser pour garder le canal le plus "propre" possible :
Fonction op :
int canal::op(char nmodo[20], char nuser[20]);
La fonction op permet de créer un modérateur. Elle ne peut être appelée que par un chanroot ou un modérateur possédant les droits. Il faut donc dans un premier temps vérifier les droits du demandeur: s'il est chanroot ou s'il est modérateur et que le champ de bit de droits le permet. La fonction ajoute une entrée dans la liste des modérateurs. A noté que le chanroot ne fait pas parti de cette liste.
Fonction deop :
int canal::deop(char nmodo[20], char nuser[20]);
Cette fonction permet de supprimer un modérateur. De même que pour op elle ne peut être appelée que par un chanroot ou un modérateur ayant les droits (comme toutes les fonctions qui vont suivre d'ailleurs). Elle supprime le nom du modérateur désiré dans la liste modérateur.
Fonction kick :
int canal::kick(char nmodo[20], char nuser[20]);
Cette fonction prend en paramètre, le nom du demandeur et le nom de la personne à supprimer. L'utilisateur concerné est alors effacer de la liste des utilisateurs du canal. Il pourra se reconnecter par la suite. Pour éviter sa reconnection il est possible de bannir l'utilisateur. Dans un premier temps la fonction doit vérifier que la personne appelant est bien un modérateur. Pour cela il suffit de chercher le nom dans la liste des modérateurs. Ensuite il faut vérifier s'il est autorisé à utiliser cette fonction dans les champs de bit des droits. On recherche maintenant le nom de la personne à kicker. Si elle existe on la supprime de la liste sinon on renvoie un message d'alerte (pas d'erreur car le nom n'est pas dans la liste des connectés, ce que nous voulions).
Fonction ban :
int canal::ban(char nmodo[20], char nuser[20]);
La fonction permet donc de bannir un utilisateur d'un canal. Un utilisateur banni ne peut plus se reconnecter au canal. La fonction ban marche sur le même principe que la fonction kick. La seule différence est que l'utilisateur est ajouté à la liste des bannis. Toutefois il faut rechercher si l'utilisateur n'est pas déjà banni pour ne pas le rebannir. Enfin il faut déconnecter l'utilisateur du canal, pour cela on utilise la fonction kick.
Fonction deban :
int canal::deban(char nmodo[20], char nuser[20]);
Le principe de cette fonction est de permettre à un utilisateur banni de pouvoir se reconnecter sur le canal. Elle marche sur le même principe que toute les fonction commençant par "de" (cf. deop). L'utilisateur demandé est supprimé dans la liste des bannis.

Gestion des chanroots

Voici les fonctions qui permettent de créer des chanroots, mais également les fonctions qui permettront de définir les modérateurs :
Fonction chanroot :
int canal::chanroot(char nchan[20], char nuser[20]);
Cette fonction permet d'ajouter un chanroot. Elle ne peut être appelée que par des chanroots. Il existe cependant deux exceptions. Le premier chanroot ne peut pas être ajouté par un autre utilisateur. De plus lorsqu'il n'y a plus de chanroots. N'importe qui peut devenir chanroot et prendre le contrôle du canal. Cette fonction vérifie que le demandeur est un chanroot, puis elle ajoute un utilisateur dans la liste des chanroots.
Fonction dechanroot :
int canal::dechanroot(char nchan[20], char nuser[20]);
Le principe de cette fonction est de permettre à un chanroot de supprimer un chanroot. Il faut savoir qu'un chanroot a la possibilité de se supprimer et de laisser, s'il était le dernier chanroot, de permettre à n'importe qui de devenir chanroot. Cette fonction est donc à utiliser avec modération. Et comme il n'y a pas de distinction entre le propriétaire et un chanroot, il vaut mieux ne pas créer trop de chanroot. La fonction fonctionne sur le même principe que les autres fonctions de suppression mais supprime dans la liste des chanroot.
Fonction chMod :
int canal::chMod(int type, int val);
Cette fonction permet de changer les droits accordés aux modérateurs du canal. Elle prends en paramètre le champ à modifier et une valeur, 0 ou 1, précisant le droit accordé ou pas. La fonction à l'intérieur modifie le champ de bit de droit en fonction du type demandé. Ainsi si on appelle (*pcanal).chMod(KICK, 1) le bit de poids faible du champ sera mis à 1, ce qui autorisera les modérateurs d'utiliser la fonction kick. Et toutes les fonctions nécessitant cette information feront un masque afin de savoir si les droits sont accordés.
Fonction de modification :
int canal::modify(char nuser[], char nchamp[],int);
Cette fonction ne peut être appelée que par le créateur du canal, ou une personne ayant les droits sur cette fonction. La modification des champs du canal se fait par le biais d'une seule fonction. La nature du champ à modifier est donnée dans le dernier paramètre. La liste des constantes est facilement modifiable dans canal.h. Par exemple pour modifier un nom on appelle la fonction ainsi : (*canal1).modify("toto", PASS);
On vérifie dans un premier temps que le demandeur ait les droits de modification. La fonction modification à l'aide de l'instruction switch modifie le type champ passé dans le deuxième paramètre. La modification est une simple mise à jour des champs.

La base de donnée

Pour représenter l'ensemble des utilisateurs, nous avons opté pour la représentation par arbre binaire et plus précisément arbre AVL (Adelson-Velskii et Landis).
L'avantage de cette représentation est que la durée de n' importe quelle opération, que ce soit ajout, insertion, suppression ou recherche, et au plus $log(n)$ où n est le nombre d'informations stockées. En effet, cela est dû à la présence de fonctions de rééquilibrage qui opèrent lors d'une insertion ou d'une suppression et maintiennent ainsi un déséquilibre au maximum de 1 en valeur absolue (le déséquilibre d'un arbre est calculé en faisant la différence entre la hauteur du fils droit de la racine et la hauteur de son fils gauche ; la hauteur étant le nombre de noeud que l'on rencontre en parcours descendant jusqu' à atteindre une feuille). Voici les différentes étapes du développement de la base de donnée :

Implémentation des types abstraits

Afin de faciliter le développement de YooGoo, nous avons implémenté en C les types les plus usités (liste, pile, file et AVL) dans notre application. Cela évite finalement que chacun d'entre nous développe ses propres outils chacun de son côté et que l'on découvre à la compilation que l'on aurait pu faire une certaine économie de temps et d'énergie.

Liste, pile et file

Pour la liste (et donc pour la pile et la file), nous avons :
  • Des éléments qui comportent un pointeur sur le suivant et un pointeur "data" qui pointe sur un élément non typé (void*) :
                typedef struct s_elt
                {
                void *data;
                struct s_elt *nxt;
                } t_elt;
    
  • Les différentes fonctions utilisées (celles classiques du type abstrait) :
    *
    Une fonction qui teste si la liste est vide.
              int     at_list_empty(t_elt *head);
    
    L'algorithme regarde si le pointeur est à NULL et retourne 1 dans ce cas.
    *
    Une fonction qui retourne la longueur de la liste.
              int     at_list_length(t_elt *head);
    
    L'algorithme parcours la liste tout en incrémentant un compteur qui est ensuite transmis en valeur de retour de la fonction.
    *
    Une fonction qui retourne l'adresse du pointeur data du ième élément de la liste.
              void    *at_list_ieme(t_elt *head, int pos);
    
    L'algorithme parcours la liste jusqu'à l'élément numéro pos et retourne son pointeur de donnée.
    *
    Une fonction qui insert un element à la place n° #place dans la liste.
              void    at_list_insert(t_elt **head, void *data, int place);
    
    L'algorithme parcours la liste et insert le nouvel élément en position numéro pos tout en prenant garde de conserver les pointeurs sur les suivants.
    *
    Une fonction qui détruit la liste et optionnellement les données en mémoire (déplacé si une autre structure y fait référence).
              void    at_list_delall(t_elt **head, int deldata);
    
    Parcours la liste tout en libèrant la mémoire pour chacun des elements.
    *
    Une function qui supprime l' element n° #place de la liste (optionnellement la donnée...)
              void    at_list_delete(t_elt **head, int place, int deldata);
    

AVL

  • Une structure ordinaire d'arbre binaire avec des pointeurs sur Type Noeud en fils gauche et fils droit :
                typedef struct s_node
                {
                void *data;
                int balance;
                struct s_node *lc;
                struct s_node *rc;
                } t_node;
    
  • Les différentes fonctions disponibles pour l'utilisateur de la librairie (l'utilisateur n'utilisera jamais les fonctions de rééquilibrages) :
    *
    Une fonction qui teste si l'arbre est une feuille (joke).
              int     at_vlt_isleaf(t_node *root);
    
    La fonction retourne si l'arbre est à NULL.
    *
    Une fonction qui insert un nouvel élément.
              int     at_vlt_insert(t_node **root,void *data,int type);
    
    Parcours l'arbre selon les critères de comparaisons définis dans at_avl_comp.c et qui varient selon la valeur de "type" qui permet de désigner le type de donnée à insèrer.
    Les AVL étant des arbres binaires de recherche, on peut utiliser les méthodes pour rechercher, ajouter ou supprimer un élément. D'après la propriété, la recherche dans un AVL contenant n éléments nécessite toujours $\theta(log n)$ comparaisons. Cependant une adjonction ou une suppression dans un AVL peuvent déséquilibrer l'arbre. Ainsi, après avoir ajouté (aux feuilles) ou supprimé un élément dans un AVL, il faut éventuellement le rééquilibrer, tout en conservant la structure d'arbre binaire de recherche.
    Voici le principe de rééquilibrage :
    Soit $T = <r,G,D>$ un AVL; supposons que l'adjonction de l'élément x a lieu sur une feuille de G et qu'elle fait augmenter de 1 la hauteur de G, et que G reste un AVL (donc avant l'adjonction, le déséquilibre de G vaut 0).
    1. Si le déséquilibre de T valait 0 avant l'adjonction, il vaut 1 après; T reste un AVL et sa hauteur a augmenté de 1.
    2. Si le déséquilibre de T valait -1 avant l'adjonction, il vaut 0 après, T reste un AVL et sa hauteur n'est pas modifiée.
    3. Si le déséquilibre de T valait +1 avant l' adjonction, il vaut +2 après : T n' est plus H-équilibré, il faut donc le restructurer en AVL.
    Dans cette troisième hypothèse, il n'y a que deux cas possibles, selon que l'adjonction a lieu dans le sous-arbre gauche ou droit de G. Dans le premier cas, le déséquilibre de G passe de 0 à 1, et on rééquilibre T par une rotation droite. Dans le deuxième cas, le déséquilibre de G passe de 0 à - 1, et on rééquilibre T par une double rotation gauche-droite. Dans les deux cas, l'arbre T obtenu après le rééquilibrage est bien un AVL (arbre binaire de recherche H-équilibré), et il retrouve exactement la hauteur qu'il avait avant l'adjonction de x.
    *
    Une fonction qui supprime tout l'arbre et optionnellement la donnée en mémoire(...).
              void    at_vlt_delall(t_node **root, int deldata);
    
    Parcours l'arbre et libère la mémoire pour chaque feuille (donc tout l'arbre, au final).
    *
    Une autre fonction, qui supprime un élément en fonction du critère de comparaison Type.
              int at_vlt_delete(t_node **root,void *data, int type, int deldata);
    
    Le principe de la suppression d'un élément dans un AVL est le même que pour les arbres binaires de recherche : remplacer l'élément à supprimer par l'élément de l'arbre qui lui est immédiatement inférieur. Mais l'arbre résultant d'une telle suppression peut ne plus être H-équilibré et il faut alors le réorganiser en arbre AVL. Le rééquilibrage après suppression fait intervenir les mêmes techniques que le rééquilibrage après adjonction; mais dans le cas d'une suppression, la réorganisation de l'arbre peut nécessiter plusieurs rotations successives, sur le chemin de la feuille supprimée jusqu'à la racine.
    La réorganisation d'un AVL après une suppression peut entraîner des rotations en cascade sur le chemin allant de la feuille supprimée jusqu'à la racine de l'arbre; en fait les rotations se propagent de bas en haut tant que la hauteur du sous-arbre réorganisé après suppression est diminuée de 1.
    L'implémentation de l'algorithme nécessite donc de mémoriser complètement un chemin de la racine à une feuille, cela peut être fait soit de façon explicite en utilisant une pile dans une version proche de celle de l'adjonction, soit de façon implicite dans une version récursive proche de la spécification formelle (attention : après la suppression d'un élément contenu dans le noeud v, il faut examiner la hauteur h du sous-arbre de racine v; si h a diminué de 1, il faut éventuellement faire une rotation au niveau du père de v).
    Une suppression dans un AVL peut entraîner jusqu'à 1.5 Log2n rotations mais la complexité reste toujours en O(log n). Comme pour l'adjonction, l'analyse en moyenne reste un problème ouvert; les résultats expérimentaux montrent cependant qu'il y a seulement en moyenne une rotation pour cinq suppressions, ce qui va donc à l'encontre du sentiment intuitif qu'une suppression est plus coûteuse qu'une adjonction!

Définition de l'objet Database

Pour " simplifier les choses ", nous avons choisi de représenter l'objet [base de donnée] (tout du moins, celui représenté en mémoire) directement par sa propre classe d'objet et ses propres méthodes qui lui seront appliquées.
La classe Base De Donnée (DB) comprend essentiellement une liste chaînée et un AVL pour chaque critère selon lesquels on peut rechercher un utilisateur.
Actuellement, on recense 4 critères principaux (Nickname, genre, date de naissance et ville). Ceci signifie que les opérations d'insertion et de suppression seront de l'ordre de $4*log(n)$.
L'objet DB comporte deux opérations classiques : le constructeur qui initialise la liste et les arbres à NULL et le destructeur qui se charge de libérer la mémoire proprement.
Il comporte également une fonction d'insertion (celle qui stock et insert dans les AVL) et une fonction de recherche qui retourne une liste chaînée d'objets utilisateurs en fonction d'un objet utilisateur passé en paramètre (critères plus ou moins vides selon ce que l'on recherche : c'est la fonction qui gère).
Bien entendu, dans le but d'être propre, les utilisateurs ne sont représentés qu'une seule fois en mémoire et les arbres s'entrecroisent sur les pointeurs "data" stockés dans la liste chaînée.
Pour cette première soutenance, un exemple en Shell sera montré, avec insertion et affichage de l' arbre ainsi que la fonctionnalité recherche.

Mais YooGoo c'est aussi

Un site web

But du Site web

Le site web doit présenter le projet. On doit y trouver toutes les informations du projet. Pour cela, il nous faut une page de news évoluée. Les différentes versions du projet ainsi que les sources doivent aussi être accessibles. N'oublions pas non plus la documentation du projet qui doit pouvoir être consultée. Pour les membres du projet, le site web est un pilier principal puisqu'il contient tout le travail de l'équipe accessible de n'importe où. Le couple PHP/SQL nous parait une bonne solution pour mettre en place un tel site.

HTML/PHP/SQL

PHP est un langage qui permet de générer du code HTML. Seul le serveur interprète le code. Pour le client, il n'y a aucune différence, il reçoit du code HTML. Une page comportant du code PHP doit comporter l'extension .php (.php3) pour que le serveur web l'interprète. Pour insérer du code PHP dans une page, on utilise la balise $<$? ... /$>$. On utilise alors la commande pour renvoyer du code HTML.
ex: echo $<$H1$>$ $\backslash$$titre $<$/H1$>$
Les variables en PHP commencent toutes avec un '$'. Il est possible d'initialiser certaines variables en appelant la page avec la syntaxe suivante.
mapage.php?var1=42;var2=53
Il est ainsi possible de transmettre des informations à d'autres pages. PHP possède un add-on qui permet de se connecter à une base SQL. SQL est un protocole permettant d'envoyer des requêtes à une base de donnée (les plus utilisées : MySQl, Oracle et MS SQL). L'instruction pour récupérer des données est:
SELECT $<$champs$>$ FROM $<$base$>$ WHERE $<$condition$>$
Par exemple si on veut récupérer le Nom et la profession de toutes les personnes de 18 ans depuis la base user, on envoiera l'instruction:
SELECT Name,Job FROM user WHERE age=18
En créant les bonnes bases, on peut rendre le couple PHP/SQL très puissant. Les principaux scripts du site web sont :
-
Les news
-
Les téléchargements
-
La Documentation
-
Les CVs
Ils ont à peu près tous le même fonctionnement. La base SQL contient les différents éléments (news/téléchargement/documentation/CVs) avec les champs:
id title text date .....
On récupère ensuite l'ensemble des éléments et on les affiche avec une boucle while toute simple. Alors qui aurait fallu recopier le code à chaque fois si on avait utilise du HTML normal (vive PHP).

PHPMyAdmin

Pour gérer la base SQL, la plupart des hébergeur possèdent un outil qui s'appelle PHPMyAdmin.
PHPMyAdmin est un outil sécurise qui permet d'avoir une vue graphique d'une base SQL. Il permet d'avoir accès facilement au commande de base de SQL ajout, suppression et recherche. Il permet aussi à l'utilisateur d'envoyer ses propres requêtes.

PHPNuke

Pour le site web, nous ne voulions pas avoir trop de travail graphique à faire. Ce n'est effectivement pas le but du projet. Bien que PHP nous aide dans cette tache, il nous semblait difficile de faire un site web sans beaucoup toucher aux logiciels graphiques. Et puis, nous avons trouvé PHPNuke. PHPNuke est un ensemble de scripts PHP qui permettent de crée un site web PHP sans quasiment toucher une ligne de code. PHPNuke nous a surtout été utile pour les fonctions pour créer l'interface graphique.
Nous avons utilise PHPNuke 5.0 pour la création de YooGoo.com. Les plus utiles des fonctions sont celles qui permettent de créer des cadres. Ca parait bête mais pour cela, il faut faire un tableau 3x3 où les cellules du bord contiennent les images des bordures. Et surtout, il faut avoir un ensemble d'images dont les dimensions sont calculées pour qu'elles correspondent avec les dimensions du tableau. Bref, ces fonctions nous ont épargné tout ce calcul laborieux.
PHPNuke possède aussi une interface pour l'administration du site web. Néanmoins, nous n'utilisons pas cette interface. Tout d'abord parce que nous avons beaucoup modifié PHPNuke pour nos besoins et que les scripts d'administrations ne sont plus compatibles. Ensuite, nous préférons utilise PHPMyAdmin qui demande une meilleure compréhension du code mais offre plus de possibilités.

MIG et Xiti

Nous avons aussi utilisé MIG, un script permettant de créé des galeries de Photos. MIG nous permet de mettre en ligne rapidement les photos numériques de Danao. Le script que nous avons utilisé était quasiment parfait pour nos besoins, nous avons donc fait que très peu de changement dessus.
Par curiosités, nous voulions savoir qui visite yoogoo.com. Nous utilisons pour cela le très célèbre Xiti. Xiti s'utilise en ajoutant simplement un petit morceau de JavaScript dans son code HTML. Xiti permet de savoir de nombreuses informations sur les internautes qui visitent le site.
Il est vrai que Xiti emmène un petit cote ludique au pauvre webmaster. YooGoo a connu une croissance supérieure a 1000% entre Novembre et Décembre. Nous affichons maintenant 55 visiteurs mensuels. Notre part de marché à l'étranger à beaucoup augmenté puisse que un tiers de nos visiteurs sont étranger (en particulier les USA, la Chine et l'Australie...). C'est vraiment super Xiti.

Choix de l'hébergeur

L'utilisation de PHP réduit énormément le choix des hébergeur. Au début nous utilisions Free.fr. Mais, nous avons été déçus par la lenteur de la connexion WWW et FTP. De plus, Free, n'accepte que PHP3 alors, que la plupart des exemples de codes se trouvent en PHP4. La grosse de différence entre PHP3 et PHP4 est que l'extension des fichiers doit être .php3 dans le premier cas et .php dans le second. Il faut donc à chaque fois modifier les extensions de tous les fichiers ainsi que toutes les références à ces fichiers. Nous avons donc essayé multimania. Multimania offre une gestion PHP4 mais le débit n'est pas beaucoup plus important que free et nous eu la surprise de voir une publicité sur notre site. Nous pensons donc utilise le serveur UNIX de Zapata qui est prêt pour héberger un site PHP4.

Une machine

Le nom de domaine YooGoo.com

Lors de la création du projet nous avions décidé de réalisé un projet aux apparences sérieuses et professionnel. C'est dans cet esprit que nous avons monté un serveur Unix réalisant la plupart des services indispensables à une petite entreprise.
Nous avons commencé par acheter YooGoo.com chez Gandi (www.gandi.net) pour 99fr. Gandi propose l'enregistrement du nom de domaine ainsi qu'un DNS (Domain Name Server). Malheureusement une telle configuration ne nous satisfaisait pas car le nom de notre site web restait yoogoo.multimania.com et non www.yoogoo.com. De plus il nous était impossible de profiter pleinement du domaine yoogoo.com. Nous avons alors décidé de monter notre propre DNS.
Le DNS qui a été installé est Named dans sa derniere version (v9.2.0a2). Ainsi nous sommes libres d'organisé notre sous domaine comme bon nous semble. L'état actuel est :
                            IN NS     Zapserv.yoogoo.com.
                            IN MX  10 mail.yoogoo.com.
        ;
        Zapserv             IN A     195.132.224.69


        www                 IN CNAME Zapserv.yoogoo.com.
        zapata              IN CNAME Zapserv.yoogoo.com.
        danao               IN CNAME danao.no-ip.com.
        hargos              IN CNAME hargos.no-ip.com.
        ftp                 IN CNAME Zapserv.yoogoo.com.
        mail                IN CNAME danao.no-ip.com.
(extrait de /etc/namebd/yoogoo.com fichier de configuration du domaine yoogoo.com)
C'est-à-dire Zapserv (le serveur principal) qui fait office de DNS a comme alias ftp, Zapata et www. Le mail @yoogoo.com est redirigé sur la machine de Franck (danao.no-ip.com) ainsi que mail.yoogoo.com. Ainsi que hargos.yoogoo.com est redirigé vers hargos.no-ip.com.

La machine et ses services

La machine qui nous sert actuellement de serveur est un PC Compaq, Pentium 120Mhz, avec 16MB de Ram, et un disque dur de 800MB, il est relié à Internet par une connexion par câble (Noos) avec un débit de 512k descendant et 128k ascendant. Cette machine est sous NetBSD 1.5 et sert de passerelle et pare-feu au réseau local de Marco (l'administrateur de la machine). Pour cela elle utilise IPNAT, IPFilter et l'IP forwarding (aussi appelé IP Masquerading). Au vue de la configuration de la machine il est clair que la charge de cette machine devra être réduite au minimum, et que le futur serveur de chat YooGoo ne tournera pas sur cette machine. (REM : Cette machine est un vrai serveur, elle est allumée 24h/24, 7j/7).
Comme on peut le constater il existe un serveur de mail pour les adresses du type login@yoogoo.com , celui ci est sur la machine de Franck. Mais il faut l'avoué cette fonction nous sert plus pour le prestige (et le coté professionnel) que pour autre chose car nous n'utilisons pas ces adresses (du moins pour l'instant). Néanmoins il existe déjà une interface graphique pour enregistrer un compte accessible au mail.yoogoo.com :81.
Il existe aussi un ftp privée sur la machine Zapserv qui nous sert pour échanger les fichiers, pour mettre les dernières versions de notre travail, et pour rendre les rapports. On essaye de le maintenir le plus a jour possible, ainsi chaque membre du groupe peut accéder a l'ensemble du travail quand il le désir. C'est un élément important car pendant les vacances il nous est parfois difficile de communiquer (et les gros fichier par mail ne sont pas acceptés, merci EPITA). Pour ce qui est de la technique du ftpd, il est lancé a partir de inetd, ainsi il n'est lancé que lorsqu'il y a des connections. De plus il est chrooted afin de protéger l'accès au fichier système.
Par ailleurs, il est aussi possible d'accéder au serveur par ssh si on a besoin de faire des opérations un peut plus complexes. Cela peut permettre aussi aux membres du groupe qui n'ont pas d'Unix chez eux d'en avoir un où ils peuvent s'amuser (sans risquer de close compte). La machine n'ayant pas d'écran, le ssh est aussi le seul moyen de l'administrer (très pratique quand on est en vacances aussi).
Enfin vient le serveur web. Comme on peut le voir à partir de la table du DNS, www.yoogoo.com est redirigé sur Zapserv. Le serveur web est apache, recompilé avec le support du php4. Puisque notre site web se base sur PHPNuke qui utilise mySQL, un serveur mySQL a été recompilé et installé pour permettre un bon fonctionnement du site web. De plus pour une administration plus aisée de mySQL, PhpMyAdmin a été installé. Un alias pour www.yooogoo.com/phpmyadmin/ a été crée, et l'accès du répertoire est protégé grâce à un mot de passe, qui fonctionne par autorisation au près de apache grâce a un .htaccess. Le serveur Unix fait donc tourner Apache/php4/mySQL/PhpMyAdmin.

Conclusion

L'opinion de chacun

Franck

Tout d'abord, j'ai du m'adapter au langage de programmation orienté objet C++ et apprendre à utiliser l'environnement Visual C++. De plus j'ai utilisé pour la première fois des classes et tout ce qui va avec, les constructeurs, les destructeurs, les fonctions statiques à la classe. La conception de la classe user principalement m'a permis de me familiariser avec la gestion des chaînes de caractères mais également avec la gestion des fichiers en ascii. De son côté la classe canal m'a permis d'approfondir mes connaissances dans les pointeurs en C et C++, et de pouvoir les manipuler.
Les recherches effectuées sur le net m'ont fait connaître l'initialisation de Winsock, les fonctions de base telles que l'émission et la réception de données ainsi que les différents modes de fonctionnement. De plus cette année le travail en groupe est mieux organisé ce qui rend le développement du projet plus efficace. Ainsi chacun comprend le principe global du serveur mais également est capable de lire et comprendre le code des autres membres du groupe.

Folken

Les expériences que m'ont apportées le travail sur le projet YooGoo sont essentiellement de deux natures différentes. La première est essentiellement humaine : j' ai enfin découvert le travail d'équipe avec des personnes sérieuses et motivées. Au sein du groupe de projet, l'ambiance est surtout au travail (peut-être trop, même), on peut constater que l'on a affaire à des passionnés intimement liés par le désir de création, mus par la soif de connaissance et de techniques (savoir et savoir-faire, pour être plus abstrait) dans le domaine informatique. La tâche est passionnante et l'environnement assez motivant. De mon côté, je n' ai aucun sentiment de regret: ma tâche est accomplie dans les délais, sinon un peu plus que prévus.
La deuxième, d'ordre plus technique, est les connaissances sur la création de base de données utilisant les AVL et diverses méthodes. J' ai également appris à mieux répartir mon temps de travail et mieux organiser mes méthodes de production. Cette expérience m'a également appris que même si certains algorithmes peuvent être déjà écris, il reste beaucoup de chemin à parcourir afin d' obtenir un résultat final satisfaisant. Au final, ces derniers sont d' ailleurs fort satisfaisants.

Hargos

Techniquement tout d'abord, j'ai appris le travail de webmaster. Pour cela, j'ai appris les langages HTML et PHP dont je ne m'était jamais servi jusqu'à présent. J'ai appris à utiliser des requêtes SQL. J'ai appris à référencer un site web. Le projet m'a permis de mettre aux C++ dans un projet de plus grande envergure que les TPs. Cette année nous avons abordé le projet avec beaucoup plus de professionnalisme que l'année dernière. Avec le protocole, j'ai appris à concevoir et à rédiger une documentation technique. Pour la planification du projet, nous nous sommes beaucoup mieux débrouillé que l'année dernière et nous avons beaucoup mieux repartis les tâches. La conception de YooGoo m'as aussi permit d'apprendre beaucoup de choses sur les réseaux et leur fonctionnement. Le projet est conforme au planning et l'entente dans le groupe est bonne. J'espère que ça va durer.

Zapata

Le travail sur la cryptographie a été très intéressant, malheureusement certaines opérations semblaient sortis de nulle part. De plus le travail sur la classe de nombre infinis m'as permis d'apprendre le C++, et de voir plus en détails la puissance des objets, tandis que les opération sur les bits dans le DES m'on fait travaillé au plus bas niveau.
Nouveau en programmation réseau, j'ai découvert les bases de Winsock, qui m'ont permis de réaliser un serveur stable et sans erreur. Il me reste à découvrir les fonctions avancées de Winsock. De plus j'ai eu une petite introduction de ce qu'est un thread, comment ça marche, comment on s'en sert et à quoi ça sert. Ce fut un travail somme toute très technique mais sûrement très utile pour l'avenir. De plus l'administration du serveur de YooGoo m'as permis d'agrandir énormément mes compétences en Unix, qui au début de l'année était bien pauvres.
Cette année s'annonce très passionnante car les sujets abordés sont variés. Jusqu'ici il m'a semblé être dans la peau d'un administrateur réseau et j'ai maintenant une idée plus précise de ce travail. Cette expérience me permettra peut-être de faire un choix mieux pesé dans mon orientation future.

Le mot de la fin

Le projet de l'année dernière porte ses fruits. La division du travail n'a pas, jusqu'à présent, posé de problèmes. Nous avons réussit à concevoir une architecture dont nous sommes sûrs (ce que nous n'avions pas fait l'année dernière). Cela nous a permis de travailler chacun sur une partie. Pour la prochaine soutenance, nous devrons réunir les codes. Nous allons pouvoir tester la cohérence de notre code. Si chacun a suivit les normes qui lui étaient imposés, il ne devrait pas y avoir de problèmes.

Annexes

Protocole

/*************************************************************************
*    Fichier: Proto.h                                                    *
*    Description: Protocole de YooGoo, decrit les fonctions              *
*       reconnus par les parseurs. Du cote client, comme du coté         *
*       serveur.                                                         *
*    Date: Janvier 2002                                                  *
**************************************************************************


////////////////////////////////////////////
/******************************************/
/* Les Commandes recue par le serveur     */
/******************************************/
////////////////////////////////////////////

/*************************************************************************
* Commande recue:                                                        *
*   chId User [Pass]                                                     *
* Permet de changer de Pseudo. Si le pseudo est deja enregisté, on doit  *
* spécifier un mot de passe. Dans le cas ou le mot de passe n'est pas    *
* specifié, la fonction doit etre appellée avec "". 'connect' previent   *
* les utilisateur ayant une conversation privée et etant connectés       *
* sur le meme canal du changement d'identité par un message 'chId'       *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_NickUnregistered                                             *
*       Err_NeedMoreParams                                               *
*       Err_Password                                                     *
*       Err_NickInUse                                                    *
*       Err_NickNotAccepted                                              *
**************************************************************************
int chId(CString user, pass);

/*************************************************************************
* Commande recue:                                                        *
*   reg User Pass                                                        *
* Permet de proteger un compte utilisateur par un mot de passe. Il n'y   *
* a pas besoin d'etre connecté sous ce nom pour l'enregister.            *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_UserRegistered                                               *
*       Err_NickInUse                                                    *
*       Err_NickNotAccepted                                              *
**************************************************************************
int reg(CString user, pass);

/*************************************************************************
* Commande recue:                                                        *
*   chNick nouveau_pseudo                                                *
* Permet de changer le champ 'Nick' de son profile.                      *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_NickInUse                                                    *
*       Err_NickNotAccepted                                              *
*       Err_NickRegistered                                               *
**************************************************************************
int chNick(CString user, new_nick);

/*************************************************************************
* Commande recue:                                                        *
*   chStatus {OnLine|Away|DND|Invisible}                                 *
* Permet de changer son status. chStatus met a jour l'index des status   *
* Attention: chStatus ne s'occuppe pas de la procedure de deconnection   *
* si 'OffLine' lui est envoyé                                            *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_InvalidStatus                                                *
*************************************************************************/
#define OFFLINE 1
#define ONLINE 2
#define AWAY 3
#define DND 4
#define INVISIBLE 5
int chStatus(CString User; int status);

/*************************************************************************
* Commande recue:                                                        *
*   chMail [nouveau_mail]                                                *
* Permet de changer le champ 'Mail' de son profile.                      *
*  Celui-ci peut-etre vide                                               *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_InvalideMail                                                 *
*************************************************************************/
int chMail(CString user, new_mail);

/*************************************************************************
* Commande recue:                                                        *
*   chName [nouveau_nom]                                                 *
* Permet de changer le champ 'Nom' de son profile.                       *
* Celui-ci peut-etre vide                                                *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*************************************************************************/
int chName(CString user, new_Name);

/*************************************************************************
* Commande recue:                                                        *
*   chFName [nouveau_prénom]                                             *
* Permet de changer le champ 'Prénom' de son profile.                    *
* Celui-ci peut-etre vide                                                *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*************************************************************************/
int chFName(CString user, new_FName);

/*************************************************************************
* Commande recue:                                                        *
*   chSex {Male|Female}                                                  *
* Permet de changer le champ 'Sexe' de son profile.                      *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_InvalidSex                                                   *
*************************************************************************/
#define MALE 1
#define FEMALE 2
int chSex(CString user; int new_sex);

/*************************************************************************
* Commande recue:                                                        *
*   chState [nouveau_pays]                                               *
* Permet de changer le champ 'Pays' de son profile.                      *
* Celui-ci peut-etre vide                                                *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*************************************************************************/
int chState(CString user, new_state);

/*************************************************************************
* Commande recue:                                                        *
*   chTown [nouvelle_ville]                                              *
* Permet de changer le champ 'Ville' de son profile. Celui-ci peut-etre  *
* vide.                                                                  *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*************************************************************************/
int chTown(CString user, new_Town);

/*************************************************************************
* Commande recue:                                                        *
*   chLikeUser user {0|1|2|...|8|9}                                      *
* Permet de changer la confiance d'un utilisateur.                       *
*                                                                        *
* 0 = liste noire                                                        *
* 1 = aucun renseignements                                               *
* 2 = utilisateur normal                                                 *
* 3 =                                                                    *
* ....                                                                   *
* 9 = tous les pouvoirs                                                  *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_NickUnregistered                                             *
*       Err_NeedMoreParams                                               *
*       Err_InvalideLevel                                                *
*************************************************************************/
int chLikeUser(CString user, user2; int like);

/*************************************************************************
* Commande recue:                                                        *
*   chPass nouveau_pass                                                  *
* Permet de changer le champ 'Password' de son profile.                  *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int chPass(CString user, new_Pass);

/*************************************************************************
* Commande recue:                                                        *
*   chAutoReply ["message"]                                              *
* Permet d'envoyer un message automatique au personne essayant de parler *
* a l'utilisateur.                                                       *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*************************************************************************/
int chAutoReply(CString user, message);

/*************************************************************************
* Commande recue:                                                        *
*   join canal [password]                                                *
* Permet de se connecter a un canal. Les autres utilisateur sont avertis *
* et la liste des connectés du canal est mise a jour                     *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChannelCreated                                               *
*       Err_NeedMoreParams                                               *
*       Err_Password                                                     *
*       Err_BannedFromChannel                                            *
*************************************************************************/
int join(CString user, chanel, password);

/*************************************************************************
* Commande recue:                                                        *
*   part canal                                                           *
* Permet de se deconnecter d'un un canal. Les autres utilisateurs sont   *
* avertis et  la  liste des connectés du canal est mise a jour           *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChannelKilled                                                *
*       Inf_NotConnectedChan                                             *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int part(CString user, chanel);

/*************************************************************************
* Commande recue:                                                        *
*   query pseudo ["message"]                                             *
* Permet d'ouvrir une discution privée avec un autre utilisateur. Une    *
* demande connection est envoyé au receiver.                             *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ConnectionRefused                                            *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int query(CString user, user, message);

/*************************************************************************
* Commande recue:                                                        *
*   query_direct pseudo ["message"]                                      *
* Permet d'ouvrir une discution privée en peer-to-peer avec un autre     *
* utilisateur. Une demande connection est envoyé au receiver.            *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ConnectionRefused                                            *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int query_direct(CString user, user, message);

/*************************************************************************
* Commande recue:                                                        *
*   msg {pseudo|canal} "message"                                         *
* Envoie un message vers un canal ou un pseudo.                          *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_NotConnectedChan                                             *
*************************************************************************/
int msg(CString user, receiver, message);

/*************************************************************************
* Commande recue:                                                        *
*   op canal pseudo                                                      *
* Donne les privileges d'Op a un User. Les autres utilisateurs sont      *
* avertis et la  liste des Op du canal est mise a jour                   *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChanNotRegistered                                            *
*       Inf_UserNotRegistered                                            *
*       Inf_Chan&UserNotRegistered                                       *
*       Inf_AlreadyOp                                                    *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int op(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   deop canal pseudo                                                    *
* Enleve les privileges d'Op a un User. Les autres utilisateurs sont     *
* avertis et la  liste des Op du canal est mise a jour                   *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_UserNotOp                                                    *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int deop(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   ban canal pseudo                                                     *
* Banni un Utilisateur du canal. Les autres utilisateurs sont avertis et *
* la  liste des Bannis du canal est mise a jour                          *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChanNotRegistered                                            *
*       Inf_UserNotRegistered                                            *
*       Inf_Chan&UserNotRegistered                                       *
*       Inf_AlreadyBan                                                   *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int ban(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   deban canal pseudo                                                   *
* Debanni un Utilisateur du canal. Les autres utilisateurs sont avertis  *
* et la liste des Bannis du canal est mise a jour                        *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_UserNotBan                                                   *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int deban(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   ChanRoot canal pseudo                                                *
* Donne les privileges de ChanRoot a un User. Les autres utilisateurs    *
* sont avertis et la  liste des ChanRoot du canal est mise a jour        *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChanNotRegistered                                            *
*       Inf_UserNotRegistered                                            *
*       Inf_Chan&UserNotRegistered                                       *
*       Inf_AlreadyChanRoot                                              *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int chanroot(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   deChanRoot canal pseudo                                              *
* Enleve les privileges de ChanRoot a un User. Les autres utilisateurs   *
* sont avertis et la liste des ChanRoot du canal est mise a jour         *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_UserNotChanRoot                                              *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int dechanroot(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   kick canal pseudo                                                    *
* Kick un Utilisateur du canal. Les autres utilisateurs sont avertis et  *
* la liste des Users du canal est mise a jour                            *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_UserNotConnected                                             *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int kick(CString user, chanel, receiver);

/*************************************************************************
* Commande recue:                                                        *
*   chMod canal {Topic|Name|                                             *
*        Kick|Op|DeOp|Ban|DeBan} {on|off}                                *
* Permet de changer les privileges des Ops sur le canal. Ne peut etre    *
* utilisé que par un chanRoot.                                           *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Inf_ChanelUnregistered                                           *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*       Err_InvalidPrivileges                                            *
*       Err_InvalidStatus                                                *
*************************************************************************/
#define TOPIC 1
#define NAME 2
#define KICK 3
#define OP 4
#define DEOP 5
#define BAN 6
#define DEBAN 7
#define OFF 0
#define ON 1
int chMod(CString user, chanel; int status, stat);

/*************************************************************************
* Commande recue:                                                        *
*   chTopic canal "Sujet"                                                *
* Permet de changer le sujet du canal                                    *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int chTopic(CString user, chanel, Topic);

/*************************************************************************
* Commande recue:                                                        *
*   chName canal Name                                                    *
* Permet de changer le Nom du canal                                      *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*************************************************************************/
int chName(CString user, chanel, Name);

/*************************************************************************
* Commande recue:                                                        *
*   chKeep canal {on|off}                                                *
* Permet de garder ou nom le canal en mémoire si il n'y a pas de         *
* connectés                                                              *
* Valeur Renvoyées:                                                      *
*       Inf_Ok                                                           *
*       Err_NeedMoreParams                                               *
*       Err_Privileges                                                   *
*       Err_ChanNotExist                                                 *
*       Err_InvalidStatus                                                *
*************************************************************************/
#define OFF 0
#define ON 1
int chKeep(CString user, chanel; int stat);

/*************************************************************************
* Commande recue:                                                        *
*   about                                                                *
* Renvoie les noms des createurs de YooGoo                               *
* Out contient la valeur renvoyée                                        *
* Valeurs Renvoyées:                                                     *
*       Rpl_About                                                        *
*************************************************************************/
int about(CString Out);

/*************************************************************************
* Commande recue:                                                        *
*   help                                                                 *
* Renvoie un texte d'aide.                                               *
* Out contient le texte renvoyé                                          *
* Valeurs Renvoyées:                                                     *
*       Rpl_About                                                        *
*************************************************************************/
int help(CString Out);

/*************************************************************************
* Commande recue:                                                        *
*   version                                                              *
* Renvoie des informations sur la serveur                                *
* Out contient la valeur renvoyée                                        *
* Valeurs Renvoyées:                                                     *
*       Rpl_Version                                                      *
*************************************************************************/
int version(CString Out);

/*************************************************************************
* Commande recue:                                                        *
*   What Cannal                                                          *
* Renvoie des informations sur le canal                                  *
* Out contient la valeur renvoyée.                                       *
* Valeurs Renvoyées:                                                     *
*       Rpl_What                                                         *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int what(CString chanel; CStringList Out);

/*************************************************************************
* Commande recue:                                                        *
*   Who Pseudo                                                           *
* Renvoie des informations sur le pseudo                                 *
* Out contient la valeur renvoyée                                        *
* Valeurs Renvoyées:                                                     *
*       Rpl_Who                                                          *
*       Err_NeedMoreParams                                               *
*************************************************************************/
int who(CString User; CStringList Out);

/*************************************************************************
* Commande recue:                                                        *
*   Search [Nick=Pseudo] [Age=Age]                                       *
* [Birth=Date_Naissance] [Town=Ville]                                    *
* [Sex={Male|Female}]                                                    *
* [Status={OnLine|OffLine}]                                              *
* Recherche les utilisateurs correspondant aux critères.                 *
*  Out contient la valeur renvoyée                                       *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       Rpl_UserNotFound                                                 *
*       Rpl_UserFound                                                    *
*       Err_NeedMoreParams                                               *
*       Err_InvalidArguments                                             *
*************************************************************************/
int search(CString Nick,Birth,Town,State; int Sex, Status; CStringList Out);

/*************************************************************************
* Commande recue:                                                        *
*   List                                                                 *
* (Si on est motive, on pourra gerer la recherche parmis les nom des     *
* canaux). Renvoie la liste des canaux du serveur Out contient la        *
* valeur renvoyée                                                        *
* Valeurs Renvoyées:                                                     *
*       Rpl_List                                                         *
*************************************************************************/
int list(CStringList Out);

/*************************************************************************
* Commande recue:                                                        *
*   Quit                                                                 *
* Se deconnecte du serveur proprement                                    *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// Cette fonction est a voir avec la gestion du thread, etc...
int disconnect(CString User);

/*************************************************************************
* Commande recue:                                                        *
*   Iam Nick Command                                                     *
* Execute la commande en tant que Nick. Cette commande est reservée a    *
* Root                                                                   *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
int iam(CString User, CString command);

/*************************************************************************
* Commande recue:                                                        *
*   Rpl_AcceptQuery Pseudo                                               *
* Accepte la demande de conversation privée d'un utilisateur             *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       Inf_Ok                                                           *
*       Err_NoQueryAsk                                                   *
*************************************************************************/
int acceptquery(CString User, User2);

/*************************************************************************
* Commande recue:                                                        *
*   Rpl_AcceptDirectQuery Pseudo                                         *
* Accepte la demande de conversation privée d'un utilisateur             *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       Inf_Ok                                                           *
*       Err_NoQueryAsk                                                   *
*************************************************************************/
int acceptdirectquery(CString User, User2);

/*************************************************************************
* Commande recue:                                                        *
*   Rpl_DenieQuery Pseudo                                                *
* Accepte la demande de conversation privée d'un utilisateur             *
*                  *                                                     *
* Valeurs Renvoyées:                                                     *
*       Inf_Ok                                                           *
*       Err_NoQueryAsk                                                   *
*************************************************************************/
int deniequery(CString User, User2);

/*************************************************************************
* Commande recue:                                                        *
*   Rpl_DenieDirectQuery Pseudo                                          *
* Accepte la demande de conversation privée d'un utilisateur             *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       Inf_Ok                                                           *
*       Err_NoQueryAsk                                                   *
*************************************************************************/
int deniedirectquery(CString User, User2);

////////////////////////////////////////////
/******************************************/
/* Les Commandes envoyées par le serveur  */
/******************************************/
////////////////////////////////////////////

/*************************************************************************
* Commande envoyee:                                                      *
*   msg pseudo message [canal]                                           *
* Donne le message d'un utilisateur sur le canal. Si le canal est omis,  *
* le message est privé                                                   *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Join canal pseudo                                                    *
* Indique qu'un utilisateur s'est connecte                               *
* sur le canal                                                           *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Part canal pseudo                                                    *
* Indique qu'un utilisateur s'est deconnecte du canal                    *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   chTopic canal message                                                *
* Donne le nouveau sujet du canal                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Op canal pseudo                                                      *
* Indique qu'un utilisateur a ete nommé Op sur le canal                  *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   DeOp canal pseudo                                                    *
* Indique qu'un utilisateur a perdu son status d'Op sur le canal         *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   ChanRoot canal pseudo                                                *
* Indique qu'un utilisateur a ete nommé Chanroot sur le canal            *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   DeChanRoot canal pseudo                                              *
* Indique qu'un utilisateur a perdu son status de ChanRoot sur le canal  *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Ban canal pseudo                                                     *
* Indique qu'un utilisateur a ete banni du canal                         *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   DeBan canal pseudo                                                   *
* Indique qu'un utilisateur a ete debanni du canal                       *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Kick canal pseudo1 pseudo2                                           *
* Indique qu'un utilisateur s'est fait kické du canal                    *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Birthday pseudo                                                      *
* Indique que c'est l'anniversaire d'un utilisateur. Ce message n'est    *
* envoye qu'une fois par connection                                      *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   AskQuery pseudo ["message"]                                          *
* Permet d'ouvrir une discution privée avec un autre utilisateur. Une    *
* demandeconnection est envoyé au receiver.                              *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Rpl_AcceptQuery Pseudo                                           *
*       Rpl_DenieQuery Pseudo                                            *
*       Err_NeedMoreParams                                               *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   AskQuery_direct pseudo ["message"]                                   *
* Permet d'ouvrir une discution privée en peer-to-peer avec un autre     *
* utilisateur. Une demande connection est envoyé au receiver.            *
*                                                                        *
* Valeur Renvoyées:                                                      *
*       Rpl_AcceptDirectQuery Pseudo                                     *
*       Rpl_DenieDirectQuery Pseudo                                      *
*       Err_NeedMoreParams                                               *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
*  Les retours sont des messages qui renvoie l'information demandée par  *
* l'utilisateur                                                          *
*************************************************************************/

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_UserNotFound                                                     *
* Indique que votre recherche n'as obtenu aucun resultat                 *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_UserFound Nick1[, Nick2[, ...]]                                  *
* Indique que votre recherche a obtenue des resultats                    *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_List Canal1[, Canal2[, ...]]                                     *
* Indique que le message est la liste des cannaux                        *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_Version String_Version                                           *
* Indique que le message contient les infos sur le serveur               *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_Who Nick, Nom, Prenom, BirthDay....                              *
* Indique que le message contient les info sur un utilisateur            *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_What Nom, Sujet, nbr_connecte...                                 *
* Indique que le message contient les info sur un canal                  *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
* Commande envoyee:                                                      *
*   Rpl_about string_about                                               *
* Indique que le message contient les infos sur le protocole YooGoo      *
*                                                                        *
* Valeurs Renvoyées:                                                     *
*       <aucune>                                                         *
*************************************************************************/
// pas de fonction appellée sur le serveur

/*************************************************************************
*  Les erreurs 0** indique que la fonction s'est bien deroulée mais que  *
*  la fonction a une information a renvoyer                              *
*************************************************************************/

/* La commande s'est déroulée normallement  */
#define Inf_Ok 000

/* Indique que le canal que l'utilisateur vient de joindre vient d'etre  *
* créé grace a lui. Cela signifie qu'il est le premier utilisateur et    *
* qu'il acquiert les droits de chanroot                                 */
#define Inf_ChannelCreated 001

/* Indique que vous etiez le dernier utilisateur et que le canal a ete   *
* killed                                                                */
#define Inf_ChannelKilled 002

/* Indique que vous avez choisit un pseudo qui n'est pas enregistré     */
#define Inf_NickUnregistered 003

/* Indique que vous avez choisit un canal qui n'est pas enregistré      */
#define Inf_ChanNotRegistered 004

/* Indique que vous avez choisit un nick et un canal qui ne sont pas     *
* enregistrés                                                           */
#define Inf_Nick&ChanNotRegistered 005

/* Indique vous essayer de kicker un utilisateur qui n'est pas connecté  *
* au canal                                                              */
#define Inf_UserNotConnected 006

/* Indique vous essayer de deOp un utilisateur qui n'est pas Op sur le   *
* canal                                                                 */
#define Inf_UserNotOp 007

/* Indique vous essayer de deBannir un utilisateur qui n'est pas banni du*
* canal                                                                 */
#define Inf_UserNotBan 008

/* Indique vous essayer de deChanRoot un utilisateur qui n'est pas       *
* ChanRoot sur le canal                                                 */
#define Inf_UserNotChanRoot 009

/* Indique vous essayer d'Op un utilisateur qui est dej Op sur le canal */
#define Inf_AlreadyOp 010

/* Indique vous essayer de Bannir un utilisateur qui est deja banni du   *
* canal                                                                 */
#define Inf_AlreadyBan 011

/* Indique vous essayer de ChanRoot un utilisateur qui est deja          *
* ChanRoot sur le canal                                                 */
#define Inf_AlreadyChanRoot 012

/* Indique votre demande discution privée a été rejetée                 */
#define Inf_ConnectionRefused 013

/*************************************************************************
*  Les erreurs 4** sont des erreur fatales. Si elles sont renvoyées, cela*
* signifie que la commande a echouée                                     *
*************************************************************************/

/* La commande envoyée n'existe pas. Cette erreur est renvoye par le     *
* parseur                                                               */
#define Err_CommandNotFound 400

/* La commande envoyée n'as pas pu etre parsée car elle ne contient pas  *
assez d'arguments. Cette erreur est renvoye par le parseur              */
#define Err_NeedMoreParams 401

/* Le canal demandé n'existe pas                                        */
#define Err_ChanNotExist 402

/* l'utilisateur n'etes pas connecté sur le canal demandé               */
#define Err_NotConnectedChan 403

/* Vous etes bannis de ce canal                                         */
#define Err_BannedFromChannel 404

/* Vous n'avez pas les privilège requis pour executer cette action      */
#define Err_Privileges 405

/* Vous essayez de DeBannir un utilisateur qui n'est pas banni          */
#define Err_NotBanned 406

/* Vous essayez de DeOp un utilisateur qui n'est pas Op                 */
#define Err_NotOp 407

/* Vous essayez de DeChanRoot un utilisateur qui n'est pas ChanRoot     */
#define Err_NotChanRoot 408

/* Vous essayez d'utiliser un nick qui est deja enregistré              */
#define Err_NickRegistered 409

/* Le pseudo que vous essayer d'utiliser est deja attribué              */
#define Err_NickInUse 410

/* Le pseudo que vous essayer d'utiliser n'est pas valide               */
#define Err_NickNotAccepted 411

/* Les arguments de votre fonction search ne sont pas valides. Cette     *
erreur est renvoye par le parseur                                       */
#define Err_InvalidArguments 412

/* Le mail que vous essayer d'utiliser n'est pas valide. Cette erreur est*
* renvoye par le parseur                                                */
#define Err_InvalideMail 413

/* Le sexe que vous avez envoyé en argument n'est pas valide. Cette      *
* erreur est renvoye par le parseur                                     */
#define Err_InvalidSex 414

/* Le status que vous avez envoyé en argument n'est pas valide. Cette    *
* erreur est renvoye par le parseur                                     */
#define Err_InvalidStatus 415

/* Le niveau que vous avez envoyé en argument n'est pas valide. Cette    *
* erreur est renvoye par le parseur                                     */
#define Err_InvalideLevel 416

/* Le mot de passe que vous avez envoyé n'est pas valide                */
#define Err_Password 417

/* Vous essayer de repondre a une demande d'amitie qui n'existe pas     */
#define Err_NoQueryAsk 418
 
 

 
 
Documentation

FAQ
Conception du Protocole
SDK en Ligne
Télécharger SDK
Cahiers des Charges
Soutenance 1
Soutenance 2
Soutenance 3
Soutenance Finale

Comment marche...
Les Canaux
Le Profile
L'administration
La Base de Données
La Cryptographie
Winsock
Le Multithreading
 
 

 
 
Liens

Epita
EpiTarget
Hallucinetik - Zone 42
poupouill.fr.st Minosis (Spé C2)
La Spé C1
La Sup C1
 
 


 
 
made in Epita Powered by ApachePHP Scripting Language

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2000 by YooGoo Team
Des remarques, des question, des choses pas claires? Hargos@ifrance.com