martes, 6 de diciembre de 2011

Broadcast en una LAN

Varias veces me he topado con tener que hacer un pequeño servicio de descubrimiento para localizar un servicio en una LAN. Siempre caigo en la trampa de enviar los datos a las dirección de broadcast predeterminada. Y en cada uno de los intentos el broadcast no se llevaba a cabo.

El siguiente ejemplo esta hecho para Android, pero la idea es la misma para todas las plataformas, obtener la dirección IP donde se esta ejecutando nuestra aplicación y la mascara de red, con esos datos se aplica un AND y vamos obteniendo byte a byte la dirección IP.

1:  DhcpInfo dhcp = wifi.getDhcpInfo();  
2:  int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;  
3:  byte[] ip = new byte[4];  
4:  for (int i = 0; i < 4; i++)  
5:    ip[i] = (byte) ((broadcast >> i * 8) & 0xFF);  



Otra metida de pata basten comun es usar el mismo puerto en el cliente y en el servidor, por lo que al hacer el broadcast detectamos que nos llegan datos al puerto donde estamos esperando la respuesta cuando en realidad es el mensaje que acabamos de difundir por la red.

sábado, 3 de diciembre de 2011

Permisos de acceso en hilos (.Net MF)

Trabajando para un proyecto de la universidad me toco implementar el refresco automático de la interfaz de usuario de la aplicación. Básicamente era llamar a un método que recogiera las medidas de los diferentes sensores conectados a una placa Tahoe II y actualizar los valores en pantalla. Hasta ahí todo bien, una tarea que a priori no debería llevar mucho tiempo.

Lo raro era que cuando la obtención de datos se hacia solo una vez funcionaba todo correctamente, pero al introducir el Timer para realizar la actualización cada 10 segundos, empezó a generarse el error InvalidOperationException. Mi primera reacción fue alguna condición de carrera estaba jodiendo todo, pero al mirar bien la documentación me di cuenta que no era eso. Sino que desde el Timer no se tenían los permisos de acceso adecuados para llamar a un objeto de otro Thread, en este caso el hilo principal.

Resulta que usar un Thread o un Timer fue una mala elección, en su lugar la mejor opcion es usar la clase DispatcherTimer, en la que los permisos de acceso son totalmente transparentes para el programador. Y todo el problema se reduce a las siguientes lineas

1:  refreshTimer = new DispatcherTimer(currentView.Dispatcher);  
2:  refreshTimer.Interval = new TimeSpan(0, 0, periodTime);  
3:  refreshTimer.Tick +=new EventHandler(refreshRoutine);  
4:  refreshTimer.Start();  

En este caso currentView es el objeto al que queremos acceder, y refreshRoutine es el método que queremos ejecutar para actualizar la pantalla.

martes, 8 de noviembre de 2011

Introducción a DPWS

El estándar DPWS es el acrónimo de Devices Profile for Web Services, define las funcionalidades mínimas para garantizar :
  • comunicación bidireccional y de manera segura con un servicio web
  • descubrimiento dinámico de un servicio web
  • descripción de un servicio web
  • suscribirse y recibir eventos de un servicio web.
Como podemos ver en la figura 1, un dispositivo (terminal que brinda servicios) podrá albergar mas de un servicio web, y podrá manejar múltiples conexiones con diferentes clientes.

Figura 1: clientes y dispositivos.
La comunicación se hace a través de mensaje. Siempre contienen un mensaje SOAP y generalmente transportan encabezados HTTP, TCP y de IP.

Descubrimiento
El descubrimiento es el mecanismo por el que el cliente es capaz de detectar un servicio que se encuentre en su propia red. Sin embargo si el cliente y el servicio estén en redes distintas, la comunicación sera posible siempre y cuando el cliente tenga una IP y un puerto al que enviar la petición.

Los mensajes Hello, Bye, Probe y Resolve, son los que definen y hacen posible el servicio de descubrimiento. Cuando un dispositivo que brinda un servicio se conecta a la red, envía un mensaje Hello, notificando al resto de equipos de la red que esta brindando un servicio. Por otra parte si el cliente no sabe a quien acudir para hacer uso de un servicio, enviara un mensaje Probe (o Resolve en caso de estar en redes distintas). Y por ultimo si el dispositivo deja la red enviara un mensaje Bye, para que el resto se enteren de su marcha.

Los servicios se agrupan en dispositivos para evitar la saturación de redes con capacidad limitada. Por ejemplo si un dispositivo tiene 15 servicios, se enviara un solo mensaje Hello a la red anunciando que el dispositivo tiene dichos servicios, en lugar de enviar 15 mensajes, uno para cada servicio.

Descripción
Cada dispositivo tiene la habilidad de describirse a si mismo, en otras palabras, sabe que servicios brinda y es capaz de comunicárselo a los clientes.

Cuando un cliente envía la petición WS-Transfer Get SOAP ENVELOPE a un dispositivo obtendrá una respuesta con la siguiente información:
  •  Modelo (modelo, numero de modelo, fabricante, etc)
  • Dispositivo (firmware, numero de serie, etc)
  • Servicios (tipo, dirección, etc)
Los servicios también tiene la habilidad de describirse, esto podemos hacerlo una vez que sepamos los datos del dispositivo. Para saber que funcionalidades brinda un servicio lo hacemos con GetMetadata.

Eventos
Como cualquier lenguaje orientado a objetos, el DPWS nos brinda la posibilidad de sincronizar los clientes y los dispositivos mediante eventos. Los eventos son lanzados por los dispositivos y los clientes que estén suscritos podrán manejar los eventos y realizar las acciones que sean necesarias. Si por algún casual lo que nos interesa es suscribirnos a un tipo determinado de eventos, se pueden aplicar filtrados para conseguirlo.

Seguridad
El estándar no especifica una política de seguridad especifica sino que da un serie de pautas a seguir. Se recomienda:
  • firma: para validar la información de los mensajes enviados sin encriptar
  • canal seguro: comunicación punto a punto a través de TLS/SSL
  • certificado: credencial usada por un cliente o dispositivo para autentificarse
Para la próxima un ejemplo de como se crea y configura todo esto con .Net Micro Framework.

jueves, 3 de noviembre de 2011

Primeros pasos con Android

Se podría decir que en toda aplicación Android (con interfaz gráfica) tendremos tres elementos básicos: Views, Layouts y Events.

Los objetos de tipo View son todos aquellos que el usuario puede ver, es decir, texto, imágenes o botones por nombrar algunos. Los layouts nos brindaran la infraestructura necesaria para poder organizar como queremos mostrar los diferentes objetos de tipo View en la pantalla de nuestro Android. Y por ultimo los Events, son los encargados de capturar las acciones realizadas por el usuario y llevar a cabo alguna acción, por ejemplo al tocar un botón emitir un sonido.

A esto es a lo que queremos llegar:

Imagen usada de fondo fue obtenida de 140geek

Nuestro hola mundo, contiene una imagen sobre la cual se escribe el mensaje "¡Hola Mundo!" y en la parte inferior tenemos la leyenda "Tocar la pantalla para salir.".

Cuando generemos el proyecto con Eclipse o Motodev (un eclipse tuneado para desarrollar en Android), únicamente tendremos el método onCreate (nuestro "main")

1:  public class HelloWorld extends Activity {  
2:    /** Called when the activity is first created. */  
3:    @Override  
4:    public void onCreate(Bundle savedInstanceState) {  
5:      super.onCreate(savedInstanceState);  
6:    }  
7:  }  

A excepción del ultimo fragmento de código y del fichero xml, todos los fragmentos siguientes deben ir dentro del método onCreate.

Para mostrar texto en pantalla, tenemos que usar objetos de tipo TextView. En las lineas 2 y 8 obtenemos el texto con id hello y msgExit respectivamente desde el gestor de recursos. Sino queremos usar el gestor de recursos y poner una cadena de texto normal entre comillas también es valido.

1:  TextView tvHello = new TextView(this);  
2:  tvHello.setText(R.string.hello);     //obtenemos el string con id hello
3:  tvHello.setGravity(Gravity.CENTER);  //centramos el texto en la pantalla
4:  tvHello.setTextColor(Color.BLACK);   //cambiamos el color de la fuente
5:  tvHello.setTextSize(20);             //cambiamos el tamaño de la fuente
6:    
7:  TextView tvExit = new TextView(this);  
8:  tvExit.setText(R.string.msgExit);  
9:  tvExit.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);  
10:  tvExit.setTextColor(Color.BLACK);  




En el explorador de paquetes, nos encontramos con la carpeta res, donde estarán los recursos contenidos en el gestor de recursos. Si queremos agregar alguna imagen basta con copiarla a alguna de las carpetas drawable y el identificador sera el nombre del fichero. En cambio para agregar cadenas de texto, tenemos que modificar el fichero strings.xml



1:  <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
2:  <resources>  
3:    <string name="hello">¡Hola Mundo!</string>  
4:    <string name="app_name">Hola Mundo</string>  
5:    <string name="title">/dev/kmem - Hola Mundo</string>  
6:    <string name="msgExit">Tocar la pantalla para salir.</string>  
7:  </resources>  

Para no distorsionar la imagen es mejor usa un ImageView en lugar de la propiedad Background de los Layouts, porque esta ultima estrecha o estira la imagen sin respetar las proporciones.

1:  ImageView ivAndroid = new ImageView(this);  
2:  ivAndroid.setImageDrawable(getResources().getDrawable(R.drawable.android));  

Ya que tenemos creados los tres objetos que queremos mostrar al usuario, ahora tenemos que crear un layout , agregar los elementos y establecer como contenido principal el layout. Como la imagen no ocupa toda la pantalla y para evitar que queden franjas negras por encima y por debajo, cambiamos el color de fondo del layout al mismo que el de la imagen.

1:  FrameLayout layout = new FrameLayout (this);  
2:  layout.setBackgroundColor(Color.WHITE);  
3:  layout.addView(ivAndroid);  
4:  layout.addView(tvHello);  
5:  layout.addView(tvExit);  
6:    
7:  setContentView(layout);  

Y por ultimo, onTouchEvent se activa cuando el usuario toca la pantalla, y el método finish termina la ejecución del programa, por lo que cuando el usuario toque la pantalla se cerrara la aplicación.

1:    @Override  
2:    public boolean onTouchEvent(MotionEvent ev)  
3:    {  
4:        this.finish();  
5:        return true;  
6:    }  

Y con eso, tenemos nuestra primera aplicación en Android.

lunes, 31 de octubre de 2011

Reviviendo el sistema: chroot desde un Live CD

Hace unos meses instale algunos paquetes que no debía, y jodí completamente el sistema. A tal punto que este era incapaz de iniciarse. Sabiendo cuales eran los paquetes que había instalado, supuse que habría alguna manera de desinstalar los paquetes de mi sistema usando un Live CD. Luego de un buen rato me tope con chroot.


Según la documentación
chroot - run command or interactive shell with special root directory
chroot()  changes the root directory of the calling process to that specified in path.  This directory will be used for pathnames beginning with /. The root directory is inherited by all children of the calling process.
Es decir, podemos hacerle creer al sistema que el directorio raíz se encuentra en otra parte y poder hacer con él casi cualquier cosa que queramos. Su principales uso es: aislar aplicaciones del resto del sistema, ya sea por motivos de desarrollo y pruebas, seguridad  o compatibilidad.

Vamos a lo nuestro, restaurar el funcionamiento normal de nuestro sistema.


Primero tenemos que saber donde se encuentra la partición root que queremos reparar

 sudo fdisk -l  

Una vez que la hayamos localizados, tenemos que decidir donde vamos a crear la estructura virtual de nuestro sistema, en este caso lo haremos en /mnt/raiz. Por lo que tenemos que crear la carpeta que se va a usar como raíz, montar nuestro

 sudo mkdir /mnt/raiz
 sudo mount "ruta_particion" /mnt/raiz
 for i in /dev /dev/pts /proc /sys; do sudo mount -B $i /mnt/raiz$i; done  

Donde "ruta_particion" es valga la redundancia la ruta de la partición root, por ejemplo: /dev/sda5.

 sudo cp /etc/resolv.conf /mnt/raiz/etc/resolv.conf  
 sudo chroot /mnt/raiz  

Y por ultimo, tenemos que ejecutar dos ordenes mas, la primera se puede omitir sino necesitamos conexión a internet, y la segunda es la ejecución del comando chroot, así que mejor la dejamos.

 sudo cp /etc/resolv.conf /mnt/raiz/etc/resolv.conf  
 sudo chroot /mnt/raiz  

Et voila, ya estamos en condiciones de instalar/desintalar los paquetes que nos causaron el problema.

Una vez que salgamos del chroot, debemos desmontar las unidades montadas anteriormente

 for i in /dev/pts /dev /proc /sys; do sudo umount /mnt/raiz$i ; done  

Reiniciar y listo.


domingo, 30 de octubre de 2011

El porqué

A lo largo de varios años programando y usando la computadora a diario, me tope con muchas tareas repetitivas . Las cuales siempre me olvidaba como hacerlas, por lo que terminaba buscando en Google algo de información para refrescar la memoria. Así que por dicho motivo es que hago este Blog.

Dentro de él encontraran artículos técnicos mayoritariamente sobre mi lucha diaria con Linux y la programación.