moreover22 / tp1-taller

Trabajo práctico 1 - Protocolo DBUS | Taller 7542
Apache License 2.0
0 stars 0 forks source link

TP 1 - Protocolo DBUS | Taller 7542

Trabajo práctico 1 - Implementación del protocolo DBUS

Taller de programación 75.42 - FIUBA

Contenidos

Introducción

El trabajo práctico tiene como objetivo dominar el manejo de sockets, archivos y cadenas en C. Para ello se deberá implementar parte del protocolo DBUS (Desktop Bus) que comunica procesos dentro del sistema operativo. Además, se deben conseguir implementaciones abstractas y encapsuladas.

Lectura de archivos

Los comandos serán leídos desde un archivo cuya ruta fue pasada por parámetro (o del stdin si ninguno fue especificado). Cada comando se encuentra en una línea distinta, es decir están separados por el carácter \n o salto de línea. Un primer acercamiento para poder obtener el comando es: leer el comando carácter por carácter hasta toparse con el salto de línea. En ese caso, copiar esa información a un buffer y luego transmitirla con el protocolo. Sin embargo, esto no es eficiente, como la función read para leer de un archivo, es una función costosa, como el resto de las syscalls, se espera ejecutarla el menor número de veces posibles.

Otra manera de encarar el problema, reduciendo las llamadas a read, es leer de más de un byte, en este caso se elije leer 32 bytes. Esos 32 bytes se almacenará en un buffer estático (siempre tiene espacio para 32 bytes), una vez leído, se analiza si se llega al final de línea. En el caso de que no se haya encontrado, se almacenan esos 32 bytes en un buffer dinámico (este irá creciendo a medida que se agregan caracteres, en esta implementación, que se puede encontrar en common_dinamicbuffer, con un factor REDIM_PROP = 1.5) y se sigue leyendo. Caso contrario, se encontró el carácter de salto de línea:

En la siguiente iteración, si hay algo en el segundo buffer estático, se almacena su contenido en el dinámico y se sigue con el bucle.

El encargado de manejar la correcta lectura del comando será el TDA common_commandlist e interactuará con los buffers de la siguiente manera:

Diagrama de clases-buffers

Una vez obtenido un comando, el mismo se codifica según el protocolo y se envía al servidor.

Socket | Cliente - Servidor

En el trabajo se implementó una librería dedicada exclusivamente a los sockets (common_socket), la cual fue diseñada para que esté abstraída de este tp en particular y pueda ser usada en futuras oportunidades.

La misma cuenta con funciones genéricas: constructor y destructor, una función para recibir y otra para enviar, funciones para la conexión tanto del cliente (connect), como para el servidor (accept, bind_and_listen).

Este TDA, permite abstraerse de las consideraciones que hay que tener al momento de trabajar con sockets: resolver nombres de dominio, resolver nombres de servicios, intentar conectarse por múltiples caminos (hasta establecer la conexión), enviar el mensaje la cantidad de veces necesarias para que el mensaje enviado sea el correcto.

Como una capa mayor de abstracción, se implementaron los TDA client (clientlib) y de server (serverlib), evitando así trabajar directamente con el TDA socket.

Diagrama de clases-buffers

El protocolo DBUS

El protocolo brinda una serie de reglas que al momento de codificar las mensajes que serán intercambiados entre los procesos. El mismo cuanta con un header y un body.

El header contiene:

[Aclaración: En el panel de la izquierda, se encuentra los bytes expresados en hexadecimal y a la derecha su correspondiente equivalente en ASCII (si el carácter no tiene significado en la explicación, se representa con '.'). Formato similar al de el editor hexed ].

Donde el primer 6C corresponde al carácter en ASCII 'l'. Luego, 01 00 01 corresponden a llamada a método, sin flags y versión del 1 protocolo respectivamente. Estos primeros bytes permanecerán constantes para esta implementación del protoco.

 |6C 01 00 01 D6 00 00 00 | 06 00 00 00 A6 00 00 00 |  |l................|

Los primeros 4 bytes fueron analizados previamente, los siguientes D6 00 00 00 expresa el número D616 (expresado en little endian) que equivale a 21410, esto indica que el cuerpo del mensaje (el que contiene los parámetros), tiene dicha longitud medida en bytes. Los siguientes 4 bytes o palabra 06 00 00 00, se trata del id del mensaje, en este caso 616 = 610.

 |06 01 73 00 12 00 00 00 |                         |  |..s.....        |

Donde el primer byte, 06, indica que es un argumento de tipo Destino, el caracter 's' (7316 en ASCII) indica que será un argumento de tipo cadena (para esta implementación siempre será el caso). Los siguientes 4 bytes mostrarán la longitud del argumento, en este caso 1216 = 1810. Luego de estas dos palabras, se encuentra el argumento en sí:

 |06 01 73 00 12 00 00 00 | 74 61 6C 6C 65 72 2E 64 |  |..s.....taller.d|
 |62 75 73 2E 70 61 72 61 | 6D 73 00 00 00 00 00 00 |  |bus.params......|

Como se ve, se completa con ceros hasta completar dos palabras (completar a 8 bytes), esto es un requerimiento que establece el protocolo y deben ser contados en la longitud del header salvo para el último argumento.

El protocolo se encuentra más detallado en la documentación DBUS, o en el enunciado del tp.

De este análisis del protocolo, se tomaron las siguientes decisiones:

Cliente server illustration

Conclusión

El manejo de sockets conlleva a tener varias consideraciones, en todo punto de la ejecución puede llegar a fallar, con lo cual leer las cosas lo antes posibles y liberar los recursos de red para evitar inconvenientes. En cuanto al protocolo DBUS, si bien el padding al momento de codificar no es trivial en un principio, luego para decodificar hace que la lectura sea más fácil, porque es más simple segmentar el mensaje. Durante el tp, se emplearon varias veces buffers, con lo cual fue un acierto implementarlo con un TDA, esto hace que sea más cómodo para utilizar abstrayendose de la implementación y el manejo de memoria directo.

Referencias