
Samedi 5 decembre 1998

Arash Habibi

Repertoire Squelette.d


Programmes HDLC et medium


Le programme medium est un programme qui ouvre 
deux sockets de type SOCK_DGRAM et sur le domaine 
UNIX et qui s'appellent respectivement 
sock_medium1 et sock_medium2

I. medium

I.1. Principe

medium recuperer ce qui arrive de la socket sock_station1
et l'envoi sur la socket sock_station2 et reciproquement. 
Le cas echeant, medium pourra introduire des erreurs dans 
ces trames. 4 types d'erreur sont possibles : 

type=0	Pas d'erreur introduite

type=1  Sur tous les caracteres, au moins un bit est faux

type=2  La quantite d'erreur depend de la variable taux. 
	Pour taux=0 le comportement est le meme que pour type=0
	il n'y a aucune erreur introduite. 
	Pour taux=1 le comportement est le meme que pour type=1
	Pour toutes les valeurs intermediaires de taux, on a 
	des frequences d'erreur intermediaires. 

type=3  Les erreurs sont de type rafale de 8 bits faux.
	Dans chaque datagramme il y a au moins une rafale
	d'erreurs.
	
type=4  Les erreurs sont toujours de type rafale, mais la 
	frequence des rafales depend encore de taux. 
	Pour taux=0, il n'y a aucune erreur possible. 
	Pour taux=1, tout le datagramme est une rafale 
	d'erreur. Enfin pour des valeurs intermediaires
	de taux on devrait pouvoir avoir 1 ou 2 rafales
	en moyenne par datagramme. 
	
I.2. Usage

Taper medium
Quand apparait le prompt : MEDIUM :) 
taper '?' ou 'help' pour avoir les differentes
commandes possibles et qui permettent de controler
le type d'erreur et leur frequences. 


II. HDLC

II.1.Principe

Il s'agit de simuler trois couches en communication : la 
couche physique, la couche liaison et une application 
quelconque, qui utilise les services de la couche liaison. 

En l'occurrence, l'application est un simple transfert de 
fichiers.

Tel quel, le programme ne merite pas du tout le nom de 
"HDLC". Le protocole de la couche liaison consiste simplement
a prendre les paquet venant du fichier a envoyer et a les
mettre dans des trames et a les remettre a la couche physique. 
Dans l'autre sens, son role se limite a attendre les trames, 
en extraire les paquets et les remettre a la couche 
application. 

Ainsi, tant qu'il n'y a pas d'erreur, pas de retard, pas 
de trames parasite, pas de desequencement, la transmission
se passe bien. 

Des qu'on introduit les erreurs, le protocole elementaire 
qui est implante actuellement est impuissant. 



II.2. Usage 

Taper "HDLC 1" dans une fenetre et "HDLC 2" dans une autre. 
L'argument (1 ou 2) est "l'identite" de la station et lui 
permet simplement de nommer ses sockets et ses fichiers 
d'un nom different de l'autre station. Pour tout le reste, 
les deux programmes sont identiques. 

Quand apparait le prompt : HDLC1 :) 
Vous pourrez taper "envoi <totofile>" pour envoyer un fichier
Vous pourrez taper "quit" pour arreter l'application
---- ------- ----  "!ls" ou n'importe quelle autre commande shell
			pourvu que le premier caractere soit '!'.
			
On peut envoyer un fichier dans un seul sens 1->2 ou 2->1
mais on peut aussi les envoyer dans les deux sens en tapant
en meme temps "envoi <totofile>" dans les deux fenetres : 

HDLC1 :) envoi Makefile
HDLC2 :) envoi Application.c
			
Attention. La station qui recoit des trames, ne sait jamais 
si ce qu'il recoit fait partie du meme fichier que la 
trame precedente ou non. C'est au protocole de faire la 
difference. 

Pour l'instant, si vous faites 
HDLC1 :) envoi Makefile
HDLC1 :) envoi Application.c

A la reception, vous aurez un seul fichier de nom
"Recu1.hdlc2" qui contiendra les deux fichiers l'un 
a la suite de l'autre. 



II.3. Travail demande

Meme en presence d'erreur, le protocole doit envoyer 
les donnees en corrigeant les erreurs par retransmission 
et en utilisant un protocole de la famille HDLC. 

Enfin, les differents envois de fichier doivent etre
reconnus par le recepteur comme faisant partie de fichiers
differents et etre enregistres dans des fichiers differents : 
Recu1.hdlc1, Recu2.hdlc1, Recu3.hdlc1, ..., RecuN.hdlc1
(Evidemment pour le programme hdlc2, les extensions sont
de "hdlc2")

Pour ce faire, en principe vous n'avez a connaitre que les 
modules Liaison.c et LiaisonToolbox.c pour le protocole
et la structure de la trame. 

Pour les operations sur les bits vous pourrez utiliser les
fonctions du module BitABitToolbox.c 

Pour la detection d'erreur et l'encodage, 
vous pourrez utiliser les fonctions du module Detection.c

Pour l'attente d'un evenement vous utiliserez la fonction 
"Attendre" definie dans le module "Attente.c"

Enfin pour la modelisation des erreurs, vous pourrez 
regarder dans le module Erreur.c. 
Pour l'instant les rafales ne peuvent etre que de 
longueur 8 bits. Comment pourrait-on faire pour faire 
des rafales de 16 bits ? 


II.4. Fonctionnement du programme existant

Ce programme represente donc trois couches qui se communiquent
par un ensemble limite de fonctions. L'interet essentiel du 
projet reside en la couche liaison.

En realite, les couches application et physique sont pratiquement
inexistants. Mais vu a travers les fonctions a l'interface des 
couches, la couche liaison fonctionne comme si les autres 
couches etaient effectivement la. 

Voici les fonctions qu'utilise la couche liaison pour 
communiquer avec les "couches voisines" : 

II.4.1. Avec l'application : 

int    InitApplication(int identite);
	Soi disant pour lancer la couche application. 
	En realite, simplement pour gerer le dialogue avec
	l'utilisateur, et pour ouvrir les fichiers lorsque 
	c'est necessaire. 
	
void   StopApplication();
	Soi disant pour arreter l'application
	En realite pour fermer le terminal et les fichiers 
	ouverts. 

int    VersApplication(void* paquet, int taille);
	Quelque soit le format du paquet, cette fonction 
	delivre le paquet de taille "taille" a l'application 
	pour qu'elle l'enregistre dans le fichier.  
	
int OrigineApplication(void* paquet, int taille);
	Quelque soit le format du paquet, cette fonction
	va chercher le prochain paquet que l'application 
	voudrait envoyer. En realite, cette fonction va 
	simplement lire le fichier et en prendre un 
	paquet de taille "taille". 

int OrigineCmdAppli(int *commande, int *desc);
	Soi disant va chercher une information de controle venant
	de l'application (comme un CONNECT.request, DISCONNECT.request
	CONNECT.respond ou DISCONNECT.respond). En realite, c'est 
	quelque chose qui va simplement lire le terminal et qui 
	dechiffre les commandes de l'utilisateur : envoi ou quit. 
	Pour les autres commandes, la couche liaison n'est pas 
	avertie. 
	la variable desc contient la valeur du descripteur de 
	fichier de donnees qui permet a la couche liaison d'attendre
	les evenements en lecture. 
	
void   VersCmdAppli();
	Soi disant fournit a la couche application des informations
	de controle (comme un CONNECT.indication, CONNECT.confirm, 
	DISCONNECT.indication, DISCONNECT.confirm). En realite, elle
	nous sert surtout de DISCONNECT.indication. Elle indique a
	l'application que la reception du fichier courant est terminee
	et que les trames suivantes devront etre enregistres dans 
	un autre fichier. 
	Cette fonction n'est quasiment pas utilisee dans la version 
	actuelle car la couche liaison n'a pas d'information de controle
	et ne sait pas quand la reception d'un fichier est terminee. 
	
Un descripteur DataAppli
	Soi disant un point de communication avec l'application et 
	qui permet surtout a la fonction "Attendre" d'attendre
	un evenement de type "arrivee de paquet". 
	En realite, il s'agit simplement du descripteur du fichier
	a emettre, et tant que le fichier n'a pas ete entierement 
	lu, l'evenement "arrivee paquet" a toujours lieu. 
	
Un descripteur CmdAppli
	Soi disant un point de communication avec l'application et 
	qui permet surtout a la fonction "Attendre" d'attendre
	un evenement de type "arrivee commande". 
	En realite, il s'agit simplement du descripteur du 
	terminal de controle de HDLC1 ou l'utilisateur tape
	ses commandes. 
	

II.4.2 Avec la couche physique
	
int InitCouchePhysique(char *loc, char *dist);
	Soi disant pour initialiser la couche physique. 
	En realite, pour ouvrir et attacher les sockets
	qui permettront d'effectuer les transmissions. 
	
void StopCouchePhysique();
	Soi disant pour arreter la couche physique, 
	En realite, pour fermer les sockets et 
	enlever les liens correspondant du repertoire. 
	
int VersCouchePhysique(void *trame, int taille);
	Soi disant pour donner une trame a la couche 
	physique pour la transmission. En realite, 
	cette fonction ecrit directement la trame
	sur la socket. 
	
int OrigineCouchePhysique(void *trame, int *taille); 
	Soi disant pour lire une trame delivree par 
	la couche physique. En realite cette fonction 
	va lire sur la socket. 

Un descripteur DataPhys
	Soi disant un point de communication avec la 
	couche physique et qui permet surtout a la 
	fonction "Attendre" de detecter l'evenement
	"arrivee trame". En realite, ce n'est que 
	le descripteur de la socket. 
	
	
II.4.3. Autres outils. 

II.4.3.1 La fonction Attendre

int Attendre(int fd1, int fd2, int fd3, float duree);

fd1, fd2 et fd3 sont des descripteurs de fichier, 
de tube, de socket ou de terminal. 
Cette fonction est bloquante jusqu'a ce que sur
l'un des trois objets representes par ces descripteurs 
il y ait quelque chose a lire, ou alors jusqu'a ce 
que la duree "duree" (en secondes) se soit ecoulee. 
(timeout)

S'il y a quelque chose a lire sur l'objet decrit par 
fd1, (et seulement sur cet objet) alors la fonction 
rend la constante YaALireSur1__. 

S'il y a a lire sur le second descripteur, et seulement
sur ce descripteur, la valeur rendue sera YaALireSur_2_.

S'il y a a lire en meme temps sur le premier descripteur
et le deuxieme, alors la valeur rendue sera YaALireSur12_. 

S'il y a a lire sur les trois descripteurs, alors 
la valeur rendue sera YaALireSur123. 

Enfin si aucun n'est lisible et que c'est simplement la 
duree "duree" qui s'est ecoulee, alors la valeur rendue
est TIMEOUT. 

Si on ne desire pas attendre des evenements sur 3 descripteurs, 
mais sur un seul par exemple fd, on peut faire l'appel suivant : 

	evenement = Attendre(fd, RIEN, RIEN, 5.0); 

Cet appel attend pendant au plus 5 seconde que quelque chose soit 
lisible sur fd. Les seuls evenements (i.e. les seuls valeurs
de retour sont YaALireSur1__ et TIMEOUT. 

L'appel : 

	Attendre(RIEN, RIEN, RIEN, 5.0); 

Revient simplement a attendre pendant 5 secondes, sans chercher
a detecter d'evenements.

Enfin, si on ne cherche pas a declencher de timeout, alors 
on peut faire un appel comme : 

	evenement = Attendre(fd1, fd2, RIEN, 0.0); 
	
Dans ce cas, quelque soit la duree d'attente, la fonction 
ne se debloquera que si fd1 ou fd2 devient lisible. 


II.4.3.2 Les fonctions BitABit

Comme pour le TP CodeCorrecteurs, un certain nombre de 
fonctions vous permettent de manipuler les nombres 
bit a bit. Contrairement au tp code d'erreur, il ne 
s'agit pas seulement des caracteres et des shorts, mais 
de tous les types de donnees, pourvu qu'ils soient 
decrits par un pointeur et leur taille (en octets). 

Ainsi, qu'on utilise des structures, ou des 
tableaux, ou des types simples, ces fonctions vous 
permettent d'afficher leur contenu bit par bit, 
de connaitre la valeur du bit numero n et de changer 
la valeur de ce bit numero n. 

ATTENTION !!! 
Contrairement au tp code d'erreur ou le bit des unites 
etait le bit 1, ici le bit des unites est le 
bit 0. Ainsi un nombre a 8 bits a les bits 0 a 7. 
Un polynome de degre 16 a des bits allant de 0 a 16. 


II.4.3.3. La structure de donnees choisi pour la trame

Ca se passe dans define.h

Vous  devrez les mettre dans des void*. 

Si vous avez choisi un paquet de type simple ou de 
type structure, pour le mettre dans VersCouchePhys : 

	typedef struct Trame_t 
	{
		char info; 
		char controle; 
	} Trame_t; 

	...

	Trame_t trame; 

	VersCouchePhys(&trame, sizeof(Trame_t)); 

Par contre, si vous utilisez une trame ou un paquet 
de type pointeur ou tableau, alors il faudra utiliser 
les fonctions de la maniere suivante : 

	typedef char Trame_t[4]; 

	...

	Trame_t trame; 

	VersCouchePhys(trame, sizeof(Trame_t)); 

























	
	
