Air 2 (aka Athena) + ServerSocket = crossdomain needed !

Assez impatient de tester les fonctionnalités les plus importantes de Air 2, release hier matin, je suis tombé des nues.
Peut etre est ce le fait de n’avoir jamais codé de serveur “public” (en dehors de localhost) auparavant, mais je me suis heurté a un problème apparement vieux comme le monde, mais qu’on ne vous dit pas dans les releases notes.

Tout bete, le serveur s’instancie en moins de 2 et on peut faire tourner un client rapidement en local :

Serverside :

server = new ServerSocket();
server.addEventListener(Event.CONNECT, connect);
server.bind(843);
server.listen();

private function connect(e:ServerSocketConnectEvent):void { trace("client connected", e.socket); }

ClientSide :

me = new Socket("192.168.0.50", 843);
me.addEventListener(Event.CONNECT, connect);

private function connect(e:Event):void { trace('connected'); }

Ce qu’on ne vous dit pas (et qui n’était pas automatique pour moi) c’est qu’une fois le client récupéré, on peut écrire dessus comme un bytearray mais pour envoyer les données, il FAUT utiliser la méthode socket.flush(); !

Une fois ce petit désagrément passé, on peut faire dialoguer les 2 facilement… ou pas !

Testé dans le navigateur, je recois une erreur de sandbox (#2048) entre mon application “http://mon-ip/client.swf” et mon serveur. Après des nuits acharnées (aka 3h) de recherches sur le net, il y a plusieurs choses a dire pour amener a la solution :

1. Si on mets le serveur sur le port 843, on peut voir le message du client demandant le crossdomain du serveur. Il envoie la commande a laquelle on pourra répondre (voir 3.) ; si on change le port, on ne voit pas la commande et donc impossible d’envoyer le bon crossdomain (je teste encore pour voir si on peut pas contourner ca).

2. Un fichier de config permet de log des chargements de policy files. Il suffit de trouver le fichier “mm.cfg” (situé dans le dossier de session, en l’occurence pour un vista normal C:\Users\Moi\mm.cfg) et de le modifier pour qu’apparaisse :

PolicyFileLog=1
PolicyFileLogAppend=1

La seconde donnée étant pour moi a 0 par défaut. Le fichier de log se trouve ensuite dans (toujours pour moi) C:\Users\Julien\AppData\Roaming\Macromedia\Flash Player\Logs\policyfiles.txt où l’on peut admirer les différentes étapes de chargement des différents crossdomain du flashplayer.

3. Dans le cas des sockets xml (et donc notre cas), le client doit charger un crossdomain.xml spécial, avec la commande :

Security.loadPolicyFile("xmlsocket://mon-ip:843");

Ce loading spécial ne change rien a la nécéssité de mettre le serveur sur le port 843 (je n’ai pas encore trouvé pourquoi et comment changer ca). En fait on peut mettre n’importe quel port sous réserve de bien l’avoir mis partout (coté serveur, et 2 fois coté client (dans le loadPolicyFile et dans le socket).

Coté serveur, quand le client execute cette commande, on reçoit tout pareil la commande . Il faut donc lui répondre un xml de crossdomain viable, où l’on doit spécifier le port, et où l’on terminera par un byte nul pour spécifier la fin de la transaction :

server = new ServerSocket();
server.addEventListener(Event.CONNECT, connect);
server.bind(843);
server.listen();

private function connect(e:ServerSocketConnectEvent):void
{
trace("client connected", e.socket);
var client:Socket = e.socket;
client.addEventListener(ProgressEvent.SOCKET_DATA, data, false, 0, true);
}

private function data(e:ProgressEvent):void
{
var client:Socket = e.target as Socket;
var cmd:String = client.readUTFBytes(client.bytesAvailable);

switch(cmd)
{
case "<policy-file-request/>":
var ba = new ByteArray();
ba.writeUTFBytes('<cross-domain-policy>');
ba.writeUTFBytes('<allow-access-from domain="*" to-ports="8888" />');
ba.writeUTFBytes('</cross-domain-policy>');
ba.writeByte(0);
ba.position = 0;

client.writeBytes(ba, 0, ba.bytesAvailable);
client.flush();
break;
}
}

Le plus dur a été de trouver les ressources qui sont bien enfouies au fin fond d’adobe.com :)

Have fun avec les socket :]

Edit : Pour ceux (comme moi) qui esperaient pouvoir installer le runtime Air2 sur linux directement en ligne de commande, cela est impossible. Il vous faudra un x11 pour pouvoir accepter les conditions d’utilisation. Normalement, un formulaire est prévu par Adobe pour pré-accepter ces conditions, renvoyant sur un bin spécial ; Air 2 étant encore en beta, le formulaire n’existera sans doute pas tant qu’une version stable ne verra le jour.

Comment (1)

  1. Carlo wrote::

    Merci Julien

    Thursday, November 19, 2009 at 11:47 am #