lunes, 24 de marzo de 2014

Compilando C/C++ para La Fonera (MIPS)

En esta entrada quiero mostrar lo sencillo que es programar en C/C++ para la Fonera (arquitectura MIPS). En la Fonera que cogí, ya tengo instalado dd-wrt, pero da exactamente igual que se tenga OpenWRT. Hay muchos manuales por Internet para flashearlas.

Para compilar, una de las opciones es aumentar el espacio de almacenamiento de la Fonera e instalar el SDK allí. La otra opción, mucho más simple, es compilar en nuestra máquina y moverlo a la Fonera con un simple "scp", así que vamos a por esta segunda opción.

Si estás usando dd-wrt, debes activar el servicio SSH a través de su interfaz web.

Lo primero que tenemos que hacer es descargar el SDK de la página de OpenWRT para x86_64 (mirror), descomprimirlo en una carpeta, e introducir la ruta del mismo en el PATH del sistema:
 wget http://downloads.openwrt.org/kamikaze/7.06/atheros-2.6/OpenWrt-SDK-atheros-2.6-for-Linux-x86_64.tar.bz2  
 tar xvjf OpenWrt-SDK-atheros-2.6-for-Linux-x86_64.tar.bz2  
 export PATH=$PATH:~/OpenWrt-SDK-atheros-2.6-for-Linux-x86_64/staging_dir_mips/bin/  

Después, creamos un "Hola Mundo!", guardando como hello_world.c:
 #include <stdio.h>  
   
 int main()  
 {  
   printf("Hello World!\n");  
   return 0;  
 }  
   

Y lo compilamos:
 mips-linux-gcc hello_world.c -o hello  

Si en lugar de código en C, queremos compilar código en C++, el comando sería el siguiente:
 mips-linux-g++ hello_world.cc -o hello  


Lo mandamos a La Fonera con "scp" (la contraseña solicitada es la del panel de administración, y el usuario siempre root, da igual el que uses en la interfaz web):
 scp hello root@192.168.1.X:  

Entramos a la Fonera (nos pedirá la contraseña del panel de administración web, de nuevo):
 ssh root@192.168.1.X   

Y probamos nuestro "Hola Mundo!"
 root@fonera:~$ ./hello  
 Hello World!  

Et voilà!

domingo, 23 de marzo de 2014

Comunicando PHP y Python con sockets

Después de tanto tiempo sin escribir nada (¿alguna vez he escrito algo?), me voy a poner a ello!

Como parte de un proyecto algo más grande que estoy desarrollando (y que pronto dejaré libre), una de las partes es comunicar una interfaz web desarrollada en PHP y un gestor de información implementado en Python y ambos en máquinas diferentes comunicadas por red local. He optado por utilizar sockets para comunicar ambas partes, Python en modo servidor y el PHP jugando la parte cliente.

Vamos a empezar con la parte cliente (PHP):

 <?php  
 error_reporting(E_ALL);  
 $address = gethostbyname('localhost');  
 $service_port = 10000;  
   
 /* Create a TCP/IP socket */  
 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);  
   
 if ($socket === false) {  
   echo "socket_create() fails: Reason: " . socket_strerror(socket_last_error()) . "<br/>";  
 } else {  
   echo "Socket created.<br/>";  
 }  
   
 echo "Trying connect to '$address' in port '$service_port'...";  
 $result = socket_connect($socket, $address, $service_port);  
 if ($result === false) {  
   echo "socket_connect() fails. Reason: $result " . socket_strerror(socket_last_error($socket)) . "\n";  
 } else {  
   echo "OK.<br/>";  
 }  
   
 $in = "OLAKASE, I'm your POU oversized to fill more than 16 characters";  
 socket_write($socket, $in, strlen($in));  
   
 echo "Receiving...<br/>";  
 $all_out = '';  
 while ($out = socket_read($socket, 2048)) {  
   $all_out .= $out;  
 }  
   
 echo "Received: ". $all_out . "<br/>";  
   
 echo "Closing socket...<br/>";  
 socket_close($socket);  
 echo "Closed.";  
   
 ?>  

Guardamos este como client.php y pasamos a implementar el servidor (Python).


 import socket  
   
 # Create a TCP/IP socket  
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
   
 # Bind the socket to the port  
 server_address = ('localhost', 10000)  
 print 'Starting up on %s port %s' % server_address  
 sock.bind(server_address)  
   
 # Listen for incoming connections  
 sock.listen(5)  
   
 while True:  
   # Wait for a connection  
   print 'Waiting for a connection'  
   connection, client_address = sock.accept()  
   try:  
     print 'Connection from: ', client_address  
     # Receive the data in small chunks  
     try:  
       all_data = ''  
       while True:  
         data = ''  
         try:  
           data = connection.recv(16, socket.MSG_DONTWAIT)  
         except:  
           pass  
         if data:  
           all_data += data  
         else:  
           break  
       print 'Received "%s"' % all_data  
       if all_data:    
         # -------------------  
         # Process input data and generate your output info  
         # -------------------  
   
         print '** Sending info to the client **'  
         print info  
         connection.sendall(info)  
     except:  
       break    
   finally:  
     try:  
       connection.close()  
     except:  
       pass  


Lo guardamos como server.py

Abrimos una consola y ejecutamos el servidor con:

 python server.py  

Sin cerrar el servidor (obviamente), lanzamos esto para que el cliente haga una petición:

 php client.php  

Y en pantalla nos mostrará la información que ha enviado el servidor con unas pocas líneas más de debug.
La parte del cliente también se puede guardar en el directorio de nuestro servidor web (Apache, nginx...) y lanzarlo a través de una llamada al navegador.

Curiosidades:
  • En la parte servidora, se recoge la información de 16 en 16 bytes y se almacena en una cadena más grande. Aquí se podría poner algún tipo de control, para no causar un "buffer overflow" (lo mismo en la recepción de la parte cliente). 
  • Los datos que se envían (servidor) yo los quería mandar estructurados, y no una simple cadena, así que he hecho uso de JSON antes de enviarlo con "connection.sendall(info)" y así en el cliente se pueden "decodificar" a su recepción. Esta técnica también se puede usar en el cliente para solicitar los datos al servidor.
  • En el cliente, "gethostbyname('localhost');" se puede sustituir directamente por la IP.
  • He usado un puerto alto (10000) para no necesitar permisos de superusuario a la hora de ejecutar el servidor, así, si se consigue ejecutar código arbitrario, al menos tendría sólo permisos de usuario... (It's something!).
  • Al principio del post he dicho que las máquinas están comunicadas por red local, pero en este ejemplo están en la misma máquina.
  • Fin!
Referencias:
  • http://pymotw.com/2/socket/tcp.html
  • http://no.php.net/manual/en/sockets.examples.php