Corrections finales

This commit is contained in:
n07070 2020-05-12 15:23:19 +02:00
parent de00cca6c7
commit 81555b4c6a
2 changed files with 23 additions and 23 deletions

View File

@ -1,6 +1,6 @@
# 大字报
> Un grand bon en avant pour le pair à pair du XXIème siècle
> Un grand bond en avant pour le pair à pair du XXIème siècle
![Étudiants préparant le projet de réseau, 2020](header.jpg)
@ -14,9 +14,9 @@ L'utilisation se fait depuis un terminal, en ligne de commande.
## Structure et déroulement
Le programme est structuré autour du fichier `node.c`, dans lequel se trouve la fonction main. Cette fonction va se charger d'appeler les fonctions d'initialisation, et de lancer le protocole. La construction des TLV, la production d'un hash et les fonctions de gestion et d'affichage d'erreurs sont dans leurs propres fichiers, car ce sont des points qui peuvent être amenés à changer lors de l'implémentation d'extensions.
Le programme est structuré autour du fichier `node.c`, dans lequel se trouve la fonction `main()`. Cette fonction va se charger d'appeler les fonctions d'initialisation, et de lancer le protocole. La construction des TLV, la production d'un hash et les fonctions de gestion et d'affichage d'erreurs sont dans leurs propres fichiers, car ce sont des points qui peuvent être amenés à changer lors de l'implémentation d'extensions.
Le noeud n'a pas de mémoire, et va donc être intialisé à partir de 0 à chaque lancement. Entre le lancement, et le moment où l'on connaît l'ensemble des messages publiés (avec le site web comme référence, bien que ça ne soit pas forcément valide), le temps de convergance est de l'ordre de quelques secondes.
Le noeud n'a pas de mémoire, et va donc être initialisé à partir de 0 à chaque lancement. Entre le lancement, et le moment où l'on connaît l'ensemble des messages publiés (avec le site web comme référence, bien que ça ne soit pas forcément valide), le temps de convergance est de l'ordre de quelques secondes.
### Structure
@ -24,11 +24,11 @@ Le programme se découpe en 2 parties ; l'initialisation, puis la récupération
### Initialisation
Lorsque l'on éxécute le programme, on donne une URL ainsi qu'un numéro de port. Cette URL va être décodée par `getaddrinfo`, qui va nous donner >=1 adresses IP. Pour chaque adresse IP, nous crééons un pair, que l'on va marquer comme permanent. Si plusieurs adresses IP sont données, mais qu'elles correspondent à un seul pair, nous n'en utilisons qu'une seule, pour évider les congestions et autres erreurs. On y associe le numéro de port donné lors du lancement. Nous crééons aussi le socket que l'on utilisera ensuite. Nous le fixons sur le port 1212.
Lorsque l'on exécute le programme, on donne une URL ainsi qu'un numéro de port. Cette URL va être décodée par `getaddrinfo`, qui va nous donner >=1 adresses IP. Pour chaque adresse IP, nous créons un pair, que l'on va marquer comme permanent. Si plusieurs adresses IP sont données, mais qu'elles correspondent à un seul pair, nous n'en utilisons qu'une seule, pour évider les congestions et autres erreurs. On y associe le numéro de port donné lors du lancement. Nous créons aussi le socket que l'on utilisera ensuite. Nous le fixons sur le port 1212.
Par soucis de simplicité, et dans l'espoir que IPv4 disparaisse rapidement des internet, nous traitons tout les pairs comme étant en IPv6. Les adresses IPv4 sont _IPv6 mapped_. Une fois le programme lancé, on ne peux plus ajouter de pair permanent, ni les supprimer. On pourrait étendre le programme en permettant d'ajouter les pairs de façon dynamique, en les ajoutant ou supprimant. On pourrait aussi choisir de "bloquer" un pair, mais cela reste impossible en l'étant, voir la note 1.
Par soucis de simplicité, et dans l'espoir que IPv4 disparaisse rapidement des internet, nous traitons tout les pairs comme étant en IPv6. Les adresses IPv4 sont _IPv6 mapped_. Une fois le programme lancé, on ne peux plus ajouter de pair permanent, ni les supprimer. On pourrait étendre le programme en permettant d'ajouter les pairs de façon dynamique, en les ajoutant ou supprimant. On pourrait aussi choisir de "bloquer" un pair, mais cela reste impossible en l'état, voir la note 1.
Nous initialisations aussi la liste des messages, en créeant un permier message, vide. Il est vide, pour plusieurs raisons : d'une part, lorsque l'on lance le programme, on peux ne pas avoir envie de publier quoique ce soit, et de juste recevoir les messages. On peux aussi avoir envie d'effacer les messages publiés précédement. Lors de la publication de notre message, il remplacera les messages précédents connu des pairs par une phrase vide, ce qui effacera le message. À noter que, vu qu'il n'existe pas, dans le protocole de base, d'authentification, ça peux aussi être un moyen d'effacer tout les messages du réseau.¹
Nous initialisations aussi la liste des messages, en créant un premier message, vide. Il est vide, pour plusieurs raisons : d'une part, lorsque l'on lance le programme, on peux ne pas avoir envie de publier quoique ce soit, et de juste recevoir les messages. On peux aussi avoir envie d'effacer les messages publiés précédemment. Lors de la publication de notre message, il remplacera les messages précédents connu des pairs par une phrase vide, ce qui effacera le message. À noter que, vu qu'il n'existe pas, dans le protocole de base, d'authentification, ça peux aussi être un moyen d'effacer tout les messages du réseau.¹
La liste de pairs et la liste de messages sont des listes chainées simples. Elles sont suffisantes, car permettent l'ajout et la suppression. Lors de l'envoi de messages, nous devons parcourir toute la liste de pairs, et lors de la réception ou l'inondation de messages, nous devons aussi passer en revue tous les messages.
@ -36,11 +36,11 @@ Une extension possible serait de stocker le hash de chaque message, afin d'avoir
### Déroulement
Le noeud va ensuite initiliser une structure `pollfd`, une variable de délai, ainsi que deux tableaux de char. Ces derniers font 1024 bytes, ce qui est recommandé dans le projet. C'est suffisant, car un paquet ne peux pas faire plus de 1024 bytes, et nous traitons les paquets les uns à la suite des autres. La structure `pollfd` va servir lors de l'appel à la fonction `poll`, qui se charge de surveiller deux descripteurs de fichiers : `stdin`, et le socket définit lors de l'initialisation. Quand des données sont écrites dans ces fichiers, nous effectuons une lecture.
Le noeud va ensuite initialiser une structure `pollfd`, une variable de délai, ainsi que deux tableaux de char. Ces derniers font 1024 bytes, ce qui est recommandé dans le projet. C'est suffisant, car un paquet ne peux pas faire plus de 1024 bytes, et nous traitons les paquets les uns à la suite des autres. La structure `pollfd` va servir lors de l'appel à la fonction `poll`, qui se charge de surveiller deux descripteurs de fichiers : `stdin`, et le socket définit lors de l'initialisation. Quand des données sont écrites dans ces fichiers, nous effectuons une lecture.
La lecture de stdin premet de récupérer à la fois des commandes pour la gestion du noeud, ainsi que le message à publier. La lecture du socket nous permet de récupérer les paquets entrants.
La lecture de stdin permet de récupérer à la fois des commandes pour la gestion du noeud, ainsi que le message à publier. La lecture du socket nous permet de récupérer les paquets entrants.
La variable de délai est utilisée pour mettre à jour la liste de pairs, demander plus de pairs le cas échéant, et demander l'état du réseau aux autres pairs. Nous l'initialisons à une valeur inférieure à 20 secondes, car lors du lancement, nous ne connaissons rien du réseau. Pas la peine d'attendre. Une fois la première éxécution passée, nous mettons un délais de vingt à trentes secondes. C'est suffisant, car la publication de nouveaux messages sur le réseau est assez lente. Nous pourrions faire évoluer ce délais en fonction du rythme de publication de nouveaux messages.
La variable de délai est utilisée pour mettre à jour la liste de pairs, demander plus de pairs le cas échéant, et demander l'état du réseau aux autres pairs. Nous l'initialisons à une valeur inférieure à 20 secondes, car lors du lancement, nous ne connaissons rien du réseau. Pas la peine d'attendre. Une fois la première exécution passée, nous mettons un délais de vingt à trente secondes. C'est suffisant, car la publication de nouveaux messages sur le réseau est assez lente. Nous pourrions faire évoluer ce délais en fonction du rythme de publication de nouveaux messages.
#### Ajouts de nouveaux messages
@ -54,17 +54,17 @@ Ce message sera envoyé aux pairs en faisant la demande lors de l'inondation.
Lors de la réception d'un message, on effectue plusieurs vérifications. La première consiste à vérifier l'entête du paquet. Une fois cette entête validée, on ajoute le pair à la liste des pairs connus.
On passe ensuite à la validation de chaque TLV. On commence par créer un paquet vide, qui va nous servir lors du renvoi éventuel de paquet vers les pairs. Ensuite, l'un à la suite des autres, nous validons les TLVs.
On passe ensuite à la validation de chaque TLV. On commence par créer un paquet vide, qui va nous servir lors du renvoi éventuel de paquets vers les pairs. Ensuite, l'un à la suite des autres, nous validons les TLVs.
Une fois qu'un TLV est valide, nous le traitons. Si nous avons besoin de renvoyer un paquet, nous allons soit envoyer un seul TLV dans un paquet dans certains cas spécifiques, soit aggréger des TLVs dans un paquet. Celui-ci servira de buffer pour la fonction d'envoi, qui sera appelée lorsque le paquet ne peux plus accueillir de nouveaux TLV, suite à quoi le paquet sera réinitialisé afin de pouvoir le réutiliser pour des futurs envois.
Une fois qu'un TLV est valide, nous le traitons. Si nous avons besoin de renvoyer un paquet, nous allons soit envoyer un seul TLV dans un paquet dans certains cas spécifiques, soit agréger des TLVs dans un paquet. Celui-ci servira de buffer pour la fonction d'envoi, qui sera appelée lorsque le paquet ne peux plus accueillir de nouveaux TLV, suite à quoi le paquet sera réinitialisé afin de pouvoir le réutiliser pour des futurs envois.
Après avoir traité tous les TLVs reçus, nous enverrons le paquet courrant, qui peut encore contenir des TLVs non envoyés.
Après avoir traité tous les TLVs reçus, nous enverrons le paquet courant, qui peut encore contenir des TLVs non envoyés.
#### Gestion et génération des hashes.
Nous utilisons la librairie OpenSSL pour générer notre hash SHA256. Dans le cas où nous ne générons que le hash d'un seul noeud, on concatenne les données id, seqno et data (en faisant attention à convertir id et seqno en big endian) dans un même buffer et on le passe à la fonction de hashage.
Dans le cas d'un network hash, on concatenera dans un grand buffer tous les hashes de chaque donnée connue (qui sont ajoutées peu à peu dans une liste chainée de façon à ce qu'elle soit en ordre croissant par rapport à l'id) puis nous passerons ce buffer à la fonction de hashage.
Dans le cas d'un network hash, on concatènera dans un grand buffer tous les hashes de chaque donnée connue (qui sont ajoutées peu à peu dans une liste chainée de façon à ce qu'elle soit en ordre croissant par rapport à l'id) puis nous passerons ce buffer à la fonction de hashage.
On n'utilisera que les 16 premiers bytes de ces hashes.
@ -72,7 +72,7 @@ On n'utilisera que les 16 premiers bytes de ces hashes.
### TLV
Les TLVs sont représentés par un type `union TLV`, qui contient des pointeurs vers le `struct` TLV en lui-même, différent pour chaque type de TLV. Afin de garder une facilité d'accès aux TLVs, ils sont tous définit avec comme premier champs, sont type, qui est de même taille pour tout TLV.
Les TLVs sont représentés par un type `union TLV`, qui contient des pointeurs vers le `struct` TLV en lui-même, différent pour chaque type de TLV. Afin de garder une facilité d'accès aux TLVs, ils sont tous définis avec comme premier champs, sont type, qui est de même taille pour tout TLV.
### poll()
@ -88,11 +88,11 @@ Notre programme contient une variable `DEBUG_LEVEL` définie dans `debug.h`, qui
Puis, entre 1 et 9, des message de débug avec plus ou moins de détails sont affichés, ce qui permet d'avoir une idée de la "vie" du pair en temps réel. À partir de 9, l'éxécution se fait étape par étape, en appuyant sur entrée à chaque étape.
Une attention particulière est porté sur la gestion des erreurs. En effet, notre pair va essayer au maximum de continuer à vivre malgré les bugs possible. Vu qu'il est possible de recevoir tout type de message, nous préférons afficher un message d'erreur ou de débug plutôt que d'arrêter l'éxécution. À noter que le fait de ne pas avoir de pair au début n'est pas une erreure fatale, car il se peut qu'un autre pair communique avec nous, sans que nous ne le connaissions au préalable.
Une attention particulière est porté sur la gestion des erreurs. En effet, notre pair va essayer au maximum de continuer à vivre malgré les bugs possible. Vu qu'il est possible de recevoir tout type de message, nous préférons afficher un message d'erreur ou de débug plutôt que d'arrêter l'exécution. À noter que le fait de ne pas avoir de pair au début n'est pas une erreur fatale, car il se peut qu'un autre pair communique avec nous, sans que nous ne le connaissions au préalable.
## Extensions
Nous avons implémenter l'aggrégation de TLV dans un paquet.
Nous avons implémenter l'agrégation de TLV dans un paquet.
Nous vérifions la cohérence des _Node State_ ; si on reçoit un node state, on vérifie que son hash est cohérent.
@ -102,9 +102,9 @@ Si notre pair as plusieurs adresses, nous communiquons sur toutes les adresses q
Nous avons réalisé de nombreux test, y compris avec d'autres pairs, écrit par des camarades. Cela nous as permis de renforcer la robustesse de notre programme.
Nous nous ajoutions mutuellement comme pair par défault, ou alor nous formions une "chaîne", où l'on ajoute son voisin, et il ajoute un autre voisin.
Nous nous ajoutions mutuellement comme pair par défault, ou alors nous formions une "chaîne", où l'on ajoute son voisin, et il ajoute un autre voisin.
Nous avons aussi essayé de faire du renvoi de paquet depuis WireShark, afin de tester la réaction de notre pair à la réception de plusieurs paquets identiques, ou de messages tronqués, corrompu, ou malveillant...
Nous avons aussi essayé de faire du renvoi de paquet depuis WireShark, afin de tester la réaction de notre pair à la réception de plusieurs paquets identiques, ou de messages tronqués, corrompu, ou malveillants...
Toutefois, la licence AGPL s'applique toujours ; aucune garantie n'est possible...

View File

@ -18,12 +18,12 @@ _Ce logiciel est développé pour GNU/Linux, et n'a pas de support à l'heure ac
- `gcc` >= 9.3.0
- `libssl-dev` et `libssl`.
- Lancez la commande `make`
- Si aucune erreure n'a lieu, tuto bene. Sinon, ouvrez un rapport de bug sur la page web du projet.
- Optionnel : vous pouvez installer Dazibao de façon permanante en copiant le fichier `dazibao` ainsi crée dans `/usr/bin`.
- Si aucune erreur n'a lieu, tuto bene. Sinon, ouvrez un rapport de bug sur la page web du projet.
- Optionnel : vous pouvez installer Dazibao de façon permanente en copiant le fichier `dazibao` ainsi crée dans `/usr/bin`.
## Utilisation
Si vous connaissez l'adresse d'un pair, vous pouvez éxecuter le programme avec la commande `./dazibao <root peer> <port>`, en remplacement `<root peer>` par l'URL où votre pair est disponible, et `<port>` par le port où le pair écoute.
Si vous connaissez l'adresse d'un pair, vous pouvez éxecuter le programme avec la commande `./dazibao <root peer> <port>`, en remplaçant `<root peer>` par l'URL où votre pair est disponible, et `<port>` par le port où le pair écoute.
Si vous voulez changer le niveau d'affichage, vous pouvez changer la valeur de la variable `DEBUG_LEVEL`, puis refaire la commande `make`.
@ -35,11 +35,11 @@ Vous pouvez aussi lancer votre pair avec la commande `./dazibao <root peer> <por
## Contribution
Sentez vous libre de copier le code, le modifier et de nous renvoyer vos modifications tout en les décrivant avec le plus de détail possible. Vous pouvez ouvrir un _merge request_ depuis la page web du projet.
Sentez vous libre de copier le code, le modifier et de nous renvoyer vos modifications tout en les décrivant avec le plus de détails possible. Vous pouvez ouvrir un _merge request_ depuis la page web du projet.
## Notes
Ce programme est une projet réalisé lors du deuxième semestre 2020, durant le confinement dû au coronavirus, dans le cadre de la licence d'informatique de Paris-Diderot, dont les consignes sont données dans le fichier [énoncé.pdf](énoncé.pdf).
Ce programme est un projet réalisé lors du deuxième semestre 2020, durant le confinement dû au coronavirus, dans le cadre de la licence d'informatique de Paris-Diderot, dont les consignes sont données dans le fichier [énoncé.pdf](énoncé.pdf).
## Licence