Vous trouverez sur Internet, plusieurs tutoriels sur les
fonctions pour gérer les sockets avec des exemples de serveurs et de clients
écrits en langage C. Ces exemples m’ont servi à une adaptation à l’assembleur
sur le Raspberry.
Pour la partie théorique des sockets je vous renvoie à ces
tutoriels (par exemple : https://broux.developpez.com/articles/c/sockets/)
Tout d’abord, nous allons voir un petit programme amusant !! qui permet l’exécution de commandes linux d’un process à
l’autre et qui nous permettra de voir l’utilisation des fonctions nécessaires.
Ces fonctions font appel à des call system linux qui
curieusement ne sont pas référencés sur le site http://syscalls.kernelgrok.com/.
Pour retrouver les différents codes à utiliser il faut lister un fichier se
trouvant sur le raspberry avec la commande :
More /usr/include/arm-linux-gnueabihf/asm/unistd.h
Puis rechercher sur Internet, les syntaxes des commandes
pour avoir les paramètres à passer à chaque fonction.
Dans ce premier programme, nous trouvons en plus des
descriptions habituelles une structure de type sockaddr qui contient le type de
connexion à utiliser, le port ici 4444 et l’adresse IP ici 0.0.0.0.
Dans la partie code, nous
commençons par créer la socket en utilisant le call system 281 et nous vérifions
le code erreur retourné. Si la création est OK nous conservons le descripteur du
socket dans le registre r4.
Puis nous enchainons sur les fonctions bind (282) qui
affecte l’adresse contenue dans la structure à la socket
listen(284) qui
référence la socket comme passive cad en attente de connexion d’un client
accept(285) qui accepte
les connections avec la socket.
Enfin nous terminons avec les fonctions de duplication des
descripteurs des entrées sorties standard (STDIN, STDOUT et STDERR) et nous
terminons par l’appel execve qui va lancer la commande demandée à l’aide du
schell.
Après compilation, ce programme doit être lancé en arrière
plan comme ceci : testsocket &
En fait ce programme va écouter ce qui arrive sur le port
4444. Pour envoyer une commande sur ce port il faut d’abord exécuter la
commande :
netcat -vv 0.0.0.0 4444
Vous aurez le message suivant :
Connection to 0.0.0.0 4444 port [tcp/*] succeeded!
Qui indique le succès de la connexion. Il ne vous reste plus
qu’à taper des commandes linux comme ls ou uname –a pour voir s’afficher les
résultats.
Evidement dans ce cas ce programme n’a que peu d’intérêt
mais vous pouvez le lancer dans une session et la lancer la commande netcat
dans une autre session et c’est déjà plus intéressant. Je vous laisse le soin
de trouver d’autres utilisations !!!
Pour arrêter le programme il suffit d’effectuer un
control-C.
Après cette première réussite, je me suis lancé dans l’écriture
d’un programme qui accède à une page d’un site web. La page d’accueil de Google
étant assez lourde, j’ai pris comme exemple une petite page (/Exemple_01.php) du
site ordi-senior.fr mais j’ai laissé en commentaire les adresses du site google.fr
si vous voulez y accéder.
Après quelques problèmes de mise au point, ce programme
fonctionne mais il faudra le compléter par des requêtes plus élaborées et par
une analyse des pages web pour en extraire les données pertinentes !!!
Tout d’abord, j’ai remplacé la structure fixe du programme précèdent
par une structure vide dont les données seront alimentées dans le code du programme.
La réservation de l’espace nécessaire est faite dans la section .bbs.
Dans le code, nous commençons par alimenter la structure
avec l’adresse ip du site à contacter et le port. Pour les sites web, le port
est toujours 80 (attention il doit être stocké sur 2 octets). Pour l’adresse
IP, soit on stocke les 4 parties de l’adresse octet par octet soit on stocke la
totalité en hexadécimal en respectant l’ordre inverse).
Remarque : normalement, nous devrions trouver l’adresse
ip d’un site en effectuant une requête à un serveur dns mais pour l’instant il
nous faudra effectuer au préalable un ping nom_du_site pour avoir son adresse
ip et la saisir dans le programme (quoique on pourrait programmer l’appel à la
commande ping , récupérer le résultat et l’analyser pour extraire l’adresse :
exercice à faire !!).
Puis nous créons la socket avec le call system connect (281)
puis nous effectuons une connexion avec
l’identifiant de la socket et l’adresse de la structure précédente.
Si tout se passe bien nous préparons l’envoi de la requête qui
est ici une simple chaine de caractères. Comme amélioration, il faudra plutôt créer
une chaine en concaténant les informations fixes avec 2 informations variables :
la ressource demandée (ici /Exemple_01.php) et le nom de l’hôte (ici ordi-senior.fr).
La requête est envoyé avec le call system Send (289) qui nécessite de connaitre
la longueur de la requête. Nous la calculons pour la passer par r2.
Ensuite nous entrons dans une boucle de réception des
résultats. Celle-ci est nécessaire car les pages peuvent avoir des tailles
importantes et le serveur va retourner les données par bloc de la taille du
buffer. La fin des résultats est donnée par le code 0xA. Nous plaçons un zéro
binaire à la fin de chaque bloc de données lu ce qui nous permet ici de l’afficher
par notre routine standard. La fonction à utiliser est recv (291) à laquelle il
faut passer l’adresse du buffer de réception et sa longueur.
Enfin le programme se termine par la fermeture de la socket.