Parlons XMPP - épisode 9 - copie de fichiers et Jingle

goffi 8 years ago technique planet-libre parlons_xmpp jabber-xmpp Libre

(pour lire les épisodes précédents, suivez l'étiquette correspondante)

Bien que déjà répété un certain nombre de fois, je le redis : XMPP fait bien plus que de la messagerie instantanée. Une des fonctionnalités qui est apparue rapidement est la copie de fichiers, voyons cela de plus près

Le problème : XMPP étant du XML, il n'est pas vraiment adapté aux données purement binaires comme des fichiers. La solution est de passer par l'extérieur, c'est à dire une autre connexion non XML, et d'utiliser le flux XML pour la gérer, on parle de connexion « out-band ». Malheureusement, parfois il n'est pas possible d'établir cette connexion, alors on passe tout par le flux XML : c'est lent, peu efficace, mais ça fonctionne presque toujours, on parle de connexion « in-band » (qu'on pourrait traduire par « interne »).
Il y a aussi des cas où il est plus simple et efficace de rester « in-band », enfin surtout un : si on envoie très peu de données, comme une petite image (un avatar par exemple).

Comme souvent dans le monde XMPP, plusieurs solutions ont été proposées, expérimentées, parfois adoptées puis dépréciées, jusqu'à ce qu'on trouve et garde celle qui semble convenir le mieux, et qui est a priori la meilleure techniquement.
Commençons par la solution courante, appelée « Stream Initiation » (initiation de flux), elle est définie par la XEP-0095, et la copie de fichier l'utilise via la XEP-0096.

La copie de fichiers est la seule application qui utilise la XEP-0095. Nous avons 2 personnes en jeu : celle qui veut envoyer le fichier, qu'on appellera « l'expéditeur » (« sender » en anglais) et celui qui veut le recevoir, qu'on appellera « le destinataire » (« receiver » en anglais).

La XEP-0096 défini ce qu'on appelle un « profil » pour l'initiation de flux, le profil « transfert de fichier ». Elle sert principalement à transmettre les métadonnées du fichier : une description, sa taille, son nom, sa date de dernière modification, et un « hash », c'est à dire une somme de contrôle pour vérifier que le fichier a été correctement copié. C'est l'algorithme MD5 qui est utilisé ici, pourtant connu pour avoir des failles, même si elles ne sont pas dramatiques dans le cadre d'un transfert de fichier (l'expéditeur étant déjà validé par ailleurs).

Il est également possible d'indiquer une fourchette (« range ») à copier, c'est à dire un point de départ (« offset ») dans le fichier et une longueur (« length »), pratique si un transfert a été interrompu en plein milieu, par une coupure de courant par exemple.

Le reste, c'est la XEP-0095 qui s'en occupe, il s'agit juste de négocier la méthode à utiliser, le destinataire accepte ou non le flux, et choisi une des méthodes. Il y a 2 méthodes principales : la première est le transfert en interne (« In-Band Bytestreams », XEP-0047) qui se contente de transcoder les données en base64.

La deuxième (la XEP-0065, « SOCKS5 Bytestreams ») est plus intéressante, elle utilise SOCKS v5 pour établir une connexion externe (« out-band ») et tenter une connexion directe ou via un « proxy » qui est un élément externe relayant les données. L'utilisation d'un proxy est moins efficace qu'une connexion directe bien entendu (les données passent par un 3ᵉ point), mais est parfois nécessaire si une connexion directe est impossible à cause d'un pare-feu ou d'un NAT par exemple. XMPP permet, grâce à disco (la XEP-0030) de savoir automatiquement si votre serveur propose un proxy.
C'est donc la XEP-0065 qui est à l'origine du nom « proxy65 » couramment utilisé.
Petit détail qui a son importance : dans le cas du transfert direct, la connexion se fait du destinataire vers l'expéditeur (qui a ouvert un port pour l'occasion), aussi la connexion peut échouer dans beaucoup de cas (par exemple l'expéditeur est derrière un NAT). Une méthode a été faite pour améliorer la situation, mais elle n'a jamais été standardisée, vous pouvez la trouver ici : http://delta.affinix.com/specs/stream.html.

Voilà pour la méthode actuelle. Elle pose de nombreux problèmes : c'est uniquement l'expéditeur qui doit proposer et le destinataire accepte ou refuse, il n'y a pas de vraie méthode de secours (appelée « fallback » en anglais), c.-à-d. de méthode pour passer de SOCKS5 (ou « s5b ») au transfert « in-band » (ou « ibb »), et il y a souvent des difficultés pour établir une connexion directe comme expliqué au paragraphe précédent. Bref, ça n'est pas satisfaisant. Mais le problème est assez complexe, il n'est pas si simple de faire une connexion directe, c'est à dire pair à pair (ou « peer to peer » en anglais).

Heureusement, une nouvelle méthode est apparue, et elle est beaucoup plus souple et efficace : Jingle. Mais cet article étant déjà long, j'en parlerai la prochaine fois.

J'en profite pour annoncer que je vais commencer une série d'articles pour expliquer l'architecture et ce qu'on peut faire concrètement avec « Salut à Toi ».

Je vous rappelle aussi que nous avons une campagne de financement participatif en cours pour porter « Salut à Toi » sur Android et faire une version de bureau, et que nous avons bien besoin de soutien ! http://www.arizuka.com/fr/projects/libervia
Merci :)