Protomake: Um Compilador de Protocolos

Thiago Souto Maior, Igor Cananéa, Fábio Guerra, Rodrigo Araújo, Djamel Sadok, Judith Kelner

Centro de Informática, UFPE
Av. Prof. Luiz Freire, S/N, Cidade Universitária - Recife, PE

{tsmcf, icc, fga, rca4, jamel, jk} @cin.ufpe.br

Abstract. The development of network protocols is a non trivial task that demands time and effort. The available tools are currently not usable enough to create application protocols that can use TCP and UDP. Moreover, they are not a great help in the creation of an application that reflects the inital project, mainly because the description languages used tend to be very abstract. This article presents Protomake, a protocol compiler that generates equivalent source-code in C and JAVA from a protocol description. A visualization plugin for Ethereal that is able to dissect procol messages can also be genrate to help in protocol debuging. Protomake was created to ease the elaboration of new application protocols that can use UDP and/or TCP and to become a complete environment for protocol development.

Resumo. O projeto e desenvolvimento de protocolos é uma tarefa não trivial que demanda tempo e esforço. As ferramentas disponíveis atualmente não são suficientemente completas para descrever protocolos complexos, que podem utilizar TCP e UDP. Além disso, fornecem pouca ajuda na criação de uma aplicação próximo do que foi projetado inicialmente, principalmente pelo fato de suas linguagens de descrição serem muito abstratas. Este artigo apresenta o Protomake, um compilador de protocolos que gera código-fonte equivalente em C e JAVA a partir de uma descrição do protocolo, podendo gerar um plugin que descreve as mensagens dessa descrição para o analisador de protocolos Ethereal. O Protomake foi projetado para facilitar a criação de novos protocolos da camada de aplicação podendo funcionar através de UDP e/ou TCP, previsto para tornar-se um ambiente completo de desenvolvimento de protocolos.

Introdução

Protomake é um compilador de protocolos que facilita o desenvolvimento de novos protocolos e a criação de aplicações para protocolos já estabelecidos. O compilador gera, a partir de uma descrição na linguagem ETPA, um conjunto de funções e uma aplicação em uma linguagem alvo. Atualmente, as linguagens alvo suportadas são C e Java. As funções podem ser usadas como uma biblioteca de código por outros programas e a aplicação gerada é um exemplo que pode ser usado para testar se a comunicação está funcionando através do protocolo descrito. Para facilitar a depuração do protocolo, Protomake pode gerar um plugin de visualização para o Ethereal.

A linguagem de descrição usada par especificar um protocolo é simples e sucinta, permitindo ao programador preocupar-se apenas com o funcionamento do protocolo e não como essas funcionalidades vão ser implementadas. Para facilitar a implementação de funcionalidades que não fazem parte do protocolo diretamente, existe um mecanismo para utilizar funções criadas na linguagem alvo dentro do protocolo. O compilador se encarrega de gerar o código necessário para fazer a integração entre a descrição compilada e o código na linguagem alvo. Por exemplo, para um servidor de echo que envia a mensagem de volta ao cliente de forma cifrada, o desenvolvedor pode implementar a cifragem em um módulo externo e integrá-la à descrição.

Na sequência desse artigo, a seção 2 apresenta alguns trabalhos que estão relacionados com o Protomake; a seção 3 explica como uma descrição de um protocolo deve ser feito; na seção há um exemplo de um servidor de echo que utiliza boa parte dos recursos da linguagem para especificar protocolos. Por fim, a seção 5 apresenta alguns comentários finais e trabalhos

Trabalhos Relacionados

Serão relacionados nesta seção os trabalhos de maior relevância na área de geração automática de protocolos ou aqueles que influenciaram o desenvolvimento do Protomake.

APC

O Protomake foi inicialmente desenvolvido como uma extensão do APC [ref] (Austin Protocol Compiler). Este compilador utiliza uma linguagem chamada TAP (Timed Abstract Protocol), que é baseada em AP (Abstract Protocol), para estruturar o protocolo. O APC é baseado em eventos de recepção e timeout, os quais desencandeiam uma sequência de ações e estados que serão acionados. O código é gerado em C e é possível usar funções escritas em C na especificação do protocolo.

Os protocolos gerados são para a camada de aplicação e fazem uso do protocolo de transporte UDP. O APC é o único compilador que efetivamente gera uma aplicação entre os que são descritos neste trabalho. Segundo Fulaninho [ref], até o presente momento, não existe a intenção de fazer uma versão para TCP.

Esterel

Esterel [ref] é uma linguagem para programar sistemas reativos e síncronos, também utilizada para validação de protocolos. Além disso, permite a verificação e validação de sistemas reativos e o seu compilador gera sistemas para simular o protocolo criado. Esterel pode ser utilizada para gerar implementações de programas reativos em software ou hardware. O compilador de Esterel também gera código C para ser incorporado como núcleo de um programa maior que manipula dados e interface com o usuário. Embora possa ser usada para construir servidores e clientes de rede, Esterel não é uma linguagem projetada especificamente para isso.

Prolacc

Prolac [ref] é uma linguagem orientada a objetos criada para desenvolver protocolos de rede, desde os simples aos mais complexos. Para compilar códigos escritos em prolac foi desenvolvido o compilador prolacc. O objetivo da linguagem é facilitar o desenvolvimento de protocolos sem um compromisso com a corretude do mesmo, deixando isso a cargo do desenvolvedor. Embora seja possível criar protocolos complexos, a descrição é apenas um pouco melhor do que programar o protocolo diretamente em uma linguagem de propósito geral pelo fato dela ser uma linguagem orientada a objetos. Como possui uma sintaxe cheia de detalhes, o desenvolvimento de protocolos é Prolacc é lento e propenso a erros.

Promela++

Promela++ [ref] é baseada em uma linguagem de descrição abstrata de protocolos chamada Promela [ref] e sua sintaxe é semelhante a de C. É possível criar protocolos integrados (mais de uma camada) e o código gerado é eficiente, em alguns casos até mais do que se houvesse sido escrito em uma linguagem de propósito geral. Promela++ permite a verificação e validação do protocolo ao convertê-lo para Promella. Apesar de ser semelhante à linguagem C, não dispõe de alocação dinâmica de variáveis nem tem suporte a temporizadores.

Funcionalidades

É descrita nesta seção a forma de especificar protocolos no Protomake, o seu funcionamento e o que é gerado após a compilação do protocolo. Muitos detalhes serão omitidos por questões de limitação de espaço, os quais podem ser obtidos no manual [ref].

Definição do protocolo

O Protomake gera código nas linguagens alvo a partir de uma descrição simples do protocolo, especificada em ETPA (Extended TPA [ref]), a qual será detalhada ao longo desta seção. A linguagem TPA foi extendida neste trabalho para possibilitar a criação de protocolos que fazem uso de TCP e para poder integrá-la com qualquer linguagem alvo.

A linguagem ETPA possui cinco seções de definição dadas por PLUGIN, IMPORTS, MESSAGES, BEHAVIORS e PROCESSES, necessariamente nesta ordem, das quais apenas MESSAGES e PROCESSES são obrigatórias.Em PLUGIN ficam as definições que são usadas para gerar o plugin para o Ethereal. Na seção IMPORTS são declarados os arquivos de definição que são importados. Em MESSAGES especificam-se as mensagens do protocolo. É apresentado a seguir um exemplo de declaração de plugin e mensagem em ETPA.

!@Author "Igor Chaves Cananea"

!@Email "icc@cin.ufpe.br"

!@Name "ProtoMake Temporary Test Protocol"

!@Acronym "PTTP"

!@Port 9986

!@Transport tcp

import “pcp.pm”

import “../sctp.pm”

message one

begin

flags : 3 bits,

length : 8 bits,

msg : length bytes,

command : 4 bytes

end

A seção de PLUGIN é composta apenas por cabeçalhos, que começam com o símbolo “!@” seguidos de uma palavra chave e um valor. As possíveis palavras chaves são Author, Email, Name, Acronym, Port e Transport. Com exceção de Port (que deve ser um inteiro) e de Transport (que deve ser tcp ou udp), todas as palavras chaves devem ser seguidas por um string. Se não existirem cabeçalhos, o plugin não é gerado. Caso exista, apenas os cabeçalhos Author e Email são opcionais.

As mensagens são definidas utilizando a palavra-chave message seguida pelo nome da mensagem. Logo após seguem os campos da mensagem agrupados num bloco begin / end. Os tipos de campos possíveis são bits e bytes que devem ser antecedidos pela quantidade respectiva de bits ou bytes. Também poderá ser utilizado como quantificador o nome de um campo previamente descrito; neste caso, o valor do campo vai ser utilizado como número.

Para utilizar código externo na definição do protocolo, construções do tipo behaviors podem ser usadas. Ao declarar um behavior, qualquer construção da forma behavior.função(expressões) é considerada uma ação válida dentro de um processo. Dessa forma, é possível inserir funcionalidades no protocolo que não estão previstas na linguagem de especificação.

Os processos descrevem o protocolo e devem ser definidos logo após as mensagens. Ao menos um processo chamado main deve ser declarado. Outros processos definidos devem ser explicitamente iniciados através da ação start proc, onde “proc” é o nome do processo. É apresentado a seguir um exemplo de um processo que faz uso de um behavior chamado Command.

behavior Command

process main

var client: address

var a : integer

begin

rcv one from client -> Command.procces(one.command);

one.msg = "Ok!";

one.length = 3;

send one to client

end

O processo main é responsável pelo laço principal do protocolo e pode ser definido como um bloco begin / end precedido de declarações de variáveis. As variáveis podem ser dos tipos integer, range (Intervalo de números, ex. 1..10, 0..255), address (endereço para envio e recepção de mensagens por UDP), client_address, server_address (mesmo que address porém através de TCP) e array, que por sua vez pode ter elementos dos tipos listados anteriormente. O corpo do process é formado por ações que serão executadas caso suas guardas sejam satisfeitas. As guardas consistem de expressões booleanas, guardas timeout ou guardas rcv.

As guardas timeout são ativadas toda vez que o contador representado pelo identificador na guarda chega a zero. Estes contadores são inicializados com o comando act. As guardas rcv são ativadas quando uma mensagem (do tipo descrito na guarda) chega no buffer e é devidamente identificada. Em relação à prioridade de ativação dessas guardas tem-se que se nenhuma guarda com expressão booleana for satisfeita, o protocolo espera que alguma mensagem chegue para verificar se uma guarda de rcv pode ser satisfeita.

A ação pode conter os comandos de atribuições, diretivas send, diretivas rcv, behaviors, if (teste de expressão booleana), do (laço de repetição) e expressões aritméticas. A diretiva send é utilizada para enviar mensagens e a rcv para recebê-las, sendo especificadas da seguinte forma:

send mensagem to endereço

rcv mensagem from endereço

O comando if consiste de guardas seguidas de ações. A primeira guarda satisfeita é a que terá sua sequência de ações executada. Exemplo:

if expr1 ->

ações1

[] expr2 ->

ações2

...

[] exprN ->

açõesN

fi

O laço de repetição é representado nesta linguagem pelo comando do. Sua sintaxe é similar a do comando if, diferindo apenas pela quantidade de guardas permitidas, neste caso só uma. As ações são executadas enquanto a guarda for satisfeita. Exemplo:

do a < 3 ->

a := a + 1;

b := b * b;

b := b + 1

od

Geração de código

Ao compilar a especificação, o código poderá ser gerado em Java ou em C. O código gerado inclui a estrutura da mensagem, as funções do behavior e funções para codificar e decodificar a mensagem. É gerado também o plugin, caso seus dados tenham sido definidos.

Atualmente, apenas as estruturas das mensagens, suas funções de serialização, as funções do behavior e o plugin para o Ethereal são gerados. O motor do protocolo foi definido, porém ainda está sendo implementado. Com o código gerado, é possível escrever um programa que implemente o protocolo e usar as funções de serialização e desserialização para enviar e receber corretamente as mensagens.

Motor do protocolo

O motor do protocolo é composto de duas linhas de execução (threads), a de recepção de mensagens e a da máquina de estados. As duas linhas são executadas segundo o modelo concorrente produtor-consumidor, no qual o produtor é a da recepção, que coloca as mensagens recebidas numa fila, e o consumidor é a da máquina de estados, que remove as mensagens da fila quando é necessário. A remoção de uma mensagem da fila é feita quando é satisfeito um dos seguintes critérios:

Nenhuma guarda está ativa, ou seja, nenhuma expressão booleana é verdadeira. Neste caso, a mensagem é retirada da fila e a máquina de estados verifica se ela satisfaz alguma guarda rcv.

Um comando rcv é encontrado nas ações (lado direito das guardas).

Se não existirem mensagens para serem consumidas o programa espera bloqueado até que chegue alguma mensagem ou até que uma guarda timeout seja ativada.

O laço principal do protocolo verifica a cada passo os estados para determinar o próximo estado a ser executado. Diferentes fluxos de estados ativos podem ocorrer dependendo das prioridades dadas pelo usuário do programa. Tem-se a possibilidade de dar prioridade à recepção de mensagens. Neste caso toda mensagem que chega é imediatamente processada e o estado ativo antes da chegada da mensagem é colocado em uma fila, para ser executado depois do tratamento da mesma. A outra possibilidade é dar prioridade à execução do fluxo até que nenhuma guarda fique ativa. Assim, quando uma mensagem chega ela fica esperando na fila até que o fluxo ativo termine, ou que um comando rcv contido no fluxo seja executado.

Plugin do Ethereal

O Ethereal é um analisador de protocolos muito usado para monitorar pacotes que estão trafegando pela rede. Ele permite uma visualização detalhada do pacote com descrições de seus campos através de plugins de dissecação. O Protomake pode gerar um plugin para o protocolo especificado. Este plugin é simples, porém útil o suficiente para visualizar as mensagens geradas pelo protocolo.

Especificação de um protocolo em ETPA para o Protomake

Será especificado um servidor de echo para melhor ilustrar a criação de um protocolo. Esse servidor possui a característica de cifrar as mensagens antes de devolvê-las à sua origem. Ao receber a mensagem, ela é cifrada pela função encript, pertencente ao behavior Crypt para só depois ser devolvida. Se não for possível cifrar a mensagem, uma mensagem de erro é enviada.

Primeiramente é definido um cabeçalho para que o plugin para o Ethereal seja gerado, como descrito na subseção 3.1:

!@Author "Igor Chaves Cananea"

!@Email "icc@cin.ufpe.br"

!@Name "ProtoMake Crypt Protocol"

!@Acrynom "PCP"

!@Port 9986

!@Transport tcp

Em seguida, é especificada a mensagem que será usada no protocolo:

message text

begin

length : 8 bits,

msg : length bytes

end

Como neste exemplo precisa-se cifrar a mensagem e isto será feito por um componente externo à ETPA, é definido um behavior para referenciar este componente no protocolo:

behavior Crypt

Por último, serão especificados os processos que inicia o protocolo (main) e que trata a mensagem recebida (cryptMsg).

process main

var client : address

begin

rcv text from client -> start cryptMsg

end

process cryptMsg

var client : address;

const started : integer = 1

begin

started = 1 -> Crypt.encrypt(text.msg, text.length);

if text.length <> 0 ->

send text to client

[] text.length = 0 ->

text.msg := "error";

text.length := 5;

send text to client

fi;

stop

end

O processo auxiliar (cryptMsg) cifra e envia a mensagem de volta para o cliente caso não ocorra nenhum erro, caso contrário, o protocolo envia uma mensagem padrão de erro.

Conclusão

Este artigo apresenta a ferramenta Protomake, que recebe como entrada descrição de protocolos especificadas na linguagem ETPA. Esta linguagem foi extendida especialmente para o Protomake, a partir da linguagem TPA. O Protomake apresenta as vantagens de acelerar o processo de desenvolvimento de protocolos provendo ferramentas para depurar e gerar o código de mensagens e funções de apoio.

Foi apresentado um exemplo da utilização do Protomake para uma aplicação simples de um servidor de echo que cifra as mensagens antes de devolvê-las à sua origem. Como pode ser visto no exemplo, a definição do protocolo é enxuta, o que significa que a escrita de um protocolo na linguagem ETPA é rápida e prática. Uma vez que o desenvolvimento de protocolos em uma linguagem de programação é lento e sujeito a falhas (de implementação), já que o código do protocolo a ser gerado é bem maior que sua descrição, torna-se aparente a vantagem da utilização do Protomake.

Como trabalhos futuros pretende-se desenvolver extensões para o Protomake, as quais irão disponibilizar uma interface para geração de protocolos de outras camadas, tais como transporte e enlace. Além disso, é previsto o desenvolvimento da própria máquina de estados do protocolo de entrada e um módulo para sua verificação e/ou validação. Outro ponto interessante a ser ressaltado é a construção de uma interface gráfica amigável, para tornar mais simples a interação com os usuários.

Referências

MCGUIRE, Tommy Marcus and GOUDA, Mohamed G. The Austin Protocol Compiler, November 17, 2002

BASU, Anindya and MORRISETT, J. Gregory and EICKEN, Thorsten von. Promela++: A Language for Constructing Correct and Efficient Protocols, 1998

KOHLER, Eddie. Prolac: A language for protocol compilatiion, http://www.pdos.lcs.mit.edu/prolac/prolac-the.pdf

BERRY, Gérard. The Foundations of Esterel, MIT Press – Foundations of Computing Series, 2000

HOLZMANN, Gerard J. Design and Validation of Computer Protocols, Prentice Hall, 1991

Protomake: Um Compilador de Protocolos

Cesar Brod

2004-01-30T17:37:00