Travaux pratiques Infonuagique I (GIS3)
Xavier Redon
1 Introduction
Le but de ces travaux pratiques est de balayer tout le domaine des
technologies d'Internet.
-
Vous commencerez par définir un objet à commander. Cet objet peut être aussi simple
qu'un Arduino avec quelques LEDs connecté en série au PC. Mais vous pouvez allez jusqu'à un
robot mobile relié au PC par une liaison XBee (transmission série sans fil).
- Vous aurez à interpréter les trames ARP et IP/UDP reçues par l'objet ou plus exactement
l'Arduino contrôlant l'objet. Les trames seront véhiculées sur la liaison série.
- Vous programmerez une application permettant d'offrir une interface Web pour contrôler
votre objet.
2 Connexion de l'objet au réseau
Le but de cet exercice est de réaliser un réseau local entre un PC et un Arduino.
2.1 Interface Ethernet virtuelle
Pour que votre prototype de réseau local soit facilement utilisable une interface
Ethernet virtuelle va être créée sur le PC. Vos programmes peuvent créer ces interfaces
en utilisant les fonctions C ci-dessous.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#define TAP_PRINCIPAL "/dev/net/tun"
#define INTERFACE_VIRTUELLE "tap0"
int creationInterfaceVirtuelle(char *nom)
{
struct ifreq interface;
int fd,erreur;
/* Ouverture du peripherique principal */
if((fd=open(TAP_PRINCIPAL,O_RDWR))<0) return fd;
bzero(&interface,sizeof interface);
interface.ifr_flags=IFF_TAP|IFF_NO_PI|IFF_MULTI_QUEUE;
strncpy(interface.ifr_name,nom,IFNAMSIZ);
if((erreur=ioctl(fd,TUNSETIFF,(void *)&interface))<0)
{ close(fd); perror("creationInterfaceVirtuelle.ioctl"); exit(EXIT_FAILURE); }
return fd;
}
void fermetureInterfaceVirtuelle(int fd){ close(fd); }
Ecrivez un programme de test pour lire les paquets arrivant sur l'interface virtuelle
à l'aide de la primitive read. Une fois les paquets lus, affichez les sur la
sortie standard (octet par octet en hexa-décimal sur deux chiffres avec des espaces
comme séparateurs). Lancez votre programme et dans un autre terminal utilisez la
commande ifconfig pour affecter une adresse IPv4 à l'interface virtuelle tap0.
Vérifiez que la configuration de tap0 provoque un affichage de paquets par
votre programme de test.
2.2 Liaison série
.
L'échange d'information se fera par liaison série. Pour gérer le port série vous
pouvez utiliser le code donné ci-après.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <fcntl.h>
#include <termios.h>
#define PORT_SERIE "/dev/ttyUSB0"
#define VITESSE_SERIE B9600
static struct termios serie_sauve;
int ouvertureSerie(char *peripherique,int vitesse){
struct termios nouveau;
int fd=open(peripherique,O_RDWR|O_NOCTTY);
if(fd<0){perror(peripherique); exit(-1);}
tcgetattr(fd,&serie_sauve);
bzero(&nouveau,sizeof(nouveau));
nouveau.c_cflag=CLOCAL|CREAD|vitesse|CS8;
nouveau.c_iflag=0;
nouveau.c_oflag=0;
nouveau.c_lflag=0;
nouveau.c_cc[VTIME]=0;
nouveau.c_cc[VMIN]=1;
tcflush(fd,TCIFLUSH);
if(tcsetattr(fd,TCSANOW,&nouveau)<0)
{ close(fd); perror("serialInit.tcsetattr"); exit(EXIT_FAILURE); }
return fd;
}
void fermetureSerie(int fd){ tcsetattr(fd,TCSANOW,&serie_sauve); close(fd); }
Ecrivez deux programmes de test. Le premier ouvre le port série et écrit un message,
en utilisant la primitive write, sur le port série toutes les 15 secondes. Le
second programme lit sur le port série en utilisant la primitive read et affiche
les caractères reçus sur la sortie standard. Lancez vos deux programmes de test sur
deux machines connectés par un câble série croisé.
2.3 Programme "interface vers série"
Vous avez maintenant tout ce qu'il faut pour écrire le programme qui va transmettre
vers le port série les paquets reçus sur l'interface virtuelle. Vous allez ainsi
transmettre les paquets générés par la pile TCP/IP de votre machine de TP par
une liaison série. Pour que le destinataire puisse savoir où commence et où finit
le paquet vous allez utiliser le protocole SLIP. Ce protocole consiste à ajouter
le caractère 0xc0 en fin de paquet. Si ce caractère est présent dans le paquet
lui-même, il est remplacé par les deux caractères 0xdb et 0xdc. Si le
caractère d'échappement 0xdb est présent dans le paquet il est remplacé par les
deux caractères 0xdb et 0xdd.
2.4 Programme "série vers interface"
Ecrivez ensuite le programme qui lit une suite d'octets sur le port série pour
les envoyer, en tant que paquet, sur l'interface virtuelle. Il vous suffit de lire
les caractères jusqu'à tomber sur le caractère final 0xc0. Par ailleurs
il faut que ce programme puisse envoyer des paquets sur l'interface virtuelle sans
que des paquets provenant de l'interface virtuelle lui soient communiqués. Sinon ces
paquets ne pourraient pas être lus par le programme "interface vers série". Une solution
consiste à "détacher" l'interface virtuelle juste après son ouverture en utilisant le
code ci-après.
void detacheInterfaceVirtuelle(int fd){
struct ifreq ifr;
bzero(&ifr,sizeof ifr);
ifr.ifr_flags=IFF_DETACH_QUEUE;
if(ioctl(fd,TUNSETQUEUE,&ifr)<0)
{ close(fd); perror("detacheInterfaceVirtuelle.ioctl"); exit(EXIT_FAILURE); }
}
2.5 Test de votre réseau local
Connectez deux PC par un câble série croisé. Lancez vos deux programmes sur chaque PC.
Configurez les interfaces tap0 des deux PC avec des adresses IPv4 différentes mais
appartenant au même réseau IP. D'un PC tentez de vérifier la connexion en utilisant la
commande ping sur l'adresse de l'autre PC. Quand cela fonctionne montez la vitesse
de la liaison série à B115200 et tentez une connexion par ssh. Déconfigurez
les interfaces eth0 avec l'utilitaire ifdown pour vérifier que le réseau utilisé
est bien le votre.
3 Programmation de l'Arduino
Vous allez programmer l'Arduino en C.
3.1 Code fourni
Pour vous faciliter la vie une grande partie du code vous est fourni :
http://www.plil.net/~rex/Enseignement/Reseau/TP.Internet.GIS3/Arduino.tgz.
Vous y trouverez, dans serial.c, des fonctions de gestion du port série et,
dans outils.c des fonctions pour activer ou désactiver des sorties.
Les fonctions d'ouverture et de fermeture du port série ont les mêmes prototypes
que celles que vous avez utilisé sur les PC. Vous disposez même de fonctions read
et write. Vous pouvez donc ré-utiliser le code développé pour l'exercice
2.2.
Un Makefile est disponible, pour compiler il suffit de taper make. Pour
télécharger le programme sur l'Arduino, tapez make upload.
3.2 Configuration réseau
Vous devez établir une connexion réseau IP entre votre PC et votre Arduino. Pour
cela nous allons utiliser le réseau local de l'exercice 2.2. L'Arduino
est naturellement connecté par une liaison série au PC dès que le cable USB est
branché. Changez tout de même la vitesse pour revenir à 9600 bauds. Sur le PC
vous devez lancer les deux programmes habituels, interface vers série et série vers
interface. Affectez une adresse IPv4 à votre interface virtuelle tap0 et
réservez une autre adresse IPv4 dans le même réseau pour l'Arduino.
3.3 Envoi d'une réponse ARP
Adaptez pour l'Arduino votre code de lecture d'un paquet sur le port série (toujours
avec le protocole SLIP). Le paquet doit être stocké dans un tableau mais faites attention
l'Arduino ne possède que 2Ko de mémoire vive.
Vous savez que si une machine lance un paquet UDP à destination de votre Arduino, une
étape de résolution d'adresse par ARP va prendre place. Votre Arduino va donc recevoir
un paquet ARP requête auquel il doit répondre avec un paquet ARP réponse. Vérifiez que
le paquet dans votre tableau est bien un paquet ARP requête (deux champs à analyser)
et que la machine concernée est bien la vôtre (un autre champ à analyser). Si le paquet
vous est destiné, forgez le paquet de réponse et envoyez le sur la connexion série,
toujours en utilisant le protocole SLIP.
3.4 Réception d'un paquet UDP
Pour commander l'objet nous allons nous baser sur un octet de donnée UDP. Commencez
par vérifier que le paquet reçu est un paquet UDP vous concernant :
-
le champ Ethernet "type" est bien 0x0800 ;
- le champ IP numéro de version est bien 4 ;
- le champ IPv4 protocole encapsulé est bien 17 ;
- l'adresse IPv4 de destination est bien celle de votre Arduino ;
- le port UDP de destination est bien celui que vous avez fixé.
Si le paquet est le paquet UDP attendu, prenez les octets de données et effectuez l'action
correspondante sur l'objet.
Vous pouvez tester votre programme en utilisant la commande Unix ci-dessous :
echo -ne "\xff" | nc -q0 -u <adresse IP Arduino> <port UDP>
4 Application Web
Passons maintenant à l'application de commande de l'objet.
4.1 Serveur Web
Votre application doit, entre autre, se comporter comme un serveur Web. Faites en sorte d'utiliser
le port 8888 et de décoder les requêtes HTTP qui sont envoyées à votre application. Vous avez
juste besoin de trouver le nom de la page demandée mais il faut quand même lire toutes les entêtes
des requêtes. Pour faire vos tests faites en sorte de retourner une page ne contenant que le nom de
la page demandée. Attention pour cela il faut d'abord retourner les entêtes de réponse, gérez Server
et Content-Type.
4.2 Commande de l'objet connecté
Pour envoyer les ordres à l'Arduino vous devez écrire une fonction d'envoi d'un octet par UDP.
4.3 Application complète
Vous pouvez maintenant fusionner le serveur HTTP et le client UDP. Lorsque votre application reçoit une
requête HTTP pour la page principale / faites en sorte de retourner un formulaire de type GET
avec des cases à cocher. Lorsque vous recevez une requête HTTP pour la page de traitement du formulaire,
récupérez les champs et envoyez les commandes correspondantes. Si le nom de la page est autre,
vous pouvez le chercher sur le disque et envoyer le fichier correspondant en réponse. Vous pourrez ainsi
créer un site ergonomique avec du code javascript et des feuilles de style.
This document was translated from LATEX by
HEVEA.