Protomake: um compilador de protocolos

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

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

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

Abstract. This is a quite simple StarOffice document where I used "Styles" to create all the text formats needed when submiting an article to the SBC.

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 um produto próximo do que foi projetado inicialmente, principalmente pelo fato de suas linguagens de descrição serem muito abstratas. Protomake é um compilador de protocolos, previsto para se tornar um ambiente completo de desenvolvimento de protocolos, que facilita a criação de novos protocolos da camada de aplicação podendo funcionar através de UDP e/ou TCP. A partir de uma descrição do protocolo, ele gera código-fonte equivalente em C e JAVA, além de gerar um plugin que descreve as mensagens do seu protocolo para o analisador de protocolos Ethereal.

Introdução

Não há muito o que dizer. Apenas use o "Estilista" teclando <F11> ou chamando-o diretamente através do menu Formatar -> Estilista e experimente os estilos identificados por SBC-nome_do_estilo.

Observe que o estilo do primeiro parágrafo de uma seção é diferente do segundo. O do primeiro parágrafo é chamado SBC-Padrão, e o de todos os subseqüentes é chamado SBC-Parágrafo. Normalmente, o "Estilo Seguinte" está configurado para que você não precise se preocupar muito com isto.

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.

2.1 APC

O protomake foi inicialmente desnvolvido 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 que desencandeiam uma sequência de ações e estados que serão acionados. O seu foco principal é gerar protocolos com algumas garantias (como...).

Os protocolos gerados são de aplicação sobre o protocolo de transporte UDP. O APC encontra-se atualmente na versão 0.5 e é o único compilador que gera uma aplicação efetivamente entre os que são descritos neste trabalho. Segundo seu autor, até o presente momento, não existe a intenção de fazer uma versão para TCP.

2.2 Estelle

2.3 Prolac

Prolac [ref] é uma linguagem orientada a objetos criada para desenvolver protocolos de rede. A linguagem é simples o suficiente para escrever protocolos complexos. O objetivo da linguagem é facilitar o desenvolvimento de protocolos sem um compromisso com a corretude do mesmo, deixando isso a cargo do desenvolvedor. O protocolo TCP foi implementado como exemplo de utilização dessa linguagem.

2.4 Promela++

Funcionalidades

3.1 Definição do protocolo

A linguagem possui cinco seções de definição dadas por PLUGIN, IMPORTS, MESSAGES, BEHAVIORS e PROCESSES, necessariamente nesta ordem, dos quais apenas MESSAGES e PROCESSES são obrigatórios. Em PLUGIN ficam as definições que são usadas para gerar o plugin para o ethereal. Na seção seguinte, são declarados os arquivos de definição que são importados. Em MESSAGES especifica-se as mensagens do protocolo. Abaixo, um exemplo:

!@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

Os cabeçalhos começam com o símbol “!@” 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. Poderá ser utilizado como quantificador também 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 usados. Ao declarar um, quaquer construção da forma behavior.função(expressões) são consideradas ações válidas 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. Um processo chamado main é requerido como o mínimo. Outros processos definidos devem ser explicitamente iniciados pelo processo main através da ação start proc, onde “proc” é o nome do processo. A seguir, um exemplo:

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 process main é responsável pelo loop 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 numeros: 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 em 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. A prioridade de ativação dessas guardas é a seguinte: 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.

Os comandos permitidos na ação podem executar atribuições, diretivas send, diretivas rcv, behaviors, if (teste de expressão booleana), do (laço de repetição) e expressões aritméticas simples. A diretiva send é utilizada para enviar mensagens e a rcv para recebê-las, sendo escritas 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 como o comando do. Sua sintaxe é similar ao do comando if, diferindo apenas pela quantidade de guardas permitidas, que no caso do do é 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

3.2 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 e funções para codificar e decodificar a mensagem. É gerado também o plugin, caso seus dados tenham sido preenchidos no cabeçalho do arquivo.

Atualmente, apenas as estruturas das mensagens, suas funções de serialização 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 deserialização para enviar e receber corretamente as mensagens.

3.3 Motor do protocolo

O motor do protocolo é composto de dois linhas de execução: 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:

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

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

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

O loop principal do protocolo verifica a cada passo os estados para determinar o próximo a ser executado. Diferentes fluxos de estados ativos podem ocorrer dependendo das prioridades dadas pelo usuário do programa. Temos como opção dar prioridade à recepção de mensagens. Isso faria com que toda mensagem que chegasse fosse imediatamente processada e os estado ativo antes da chegada da mensagem seria colocado um uma fila para ser executado depois do tratamento da mesma. Com isso os estados poderiam ser executados intercaladamente (estados de tratamento de mensagem e estados ativos anteriormente, colocando na mesma fila também os seus respectivos próximos estados), porém esta prioridade pode causar starvation ao processo decorrente dos estados ativos anteriormente. A outra opção seria 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.

3.4 Plugin para o Ethereal

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

Especificando um protocolo

Especificaremos 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 é encriptada pela função encript, pertencente ao behavior Crypt para só depois ser devolvida. Se não for possível encriptar a mensagem, uma mensagem de erro é enviada:

Em primeiro lugar, é definido um cabeçalho para que o plugin para o Ethereal seja gerado, como descrito na seção 3.1:

!@Author "Igor Chaves Cananea"

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

!@Name "ProtoMake Crypt Protocol"

!@Acrynom "PCP"

!@Port 9986

!@Transport tcp

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

message text

begin

length : 8 bits,

msg : length bytes

end

Um behavior que será usado para encriptar a mensagem:

behavior Crypt

O processo principal que irá iniciar o processo de criptografia, caso uma mensagem seja recebida:

process main

var client : address

begin

rcv text from client -> start cryptMsg

end

O processo auxiliar que irá criptografar e enviar a mensagem de volta para o cliente:

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

Conclusão

Este artigo apresentou a ferramenta Protomake, que ... bla bla. O protomake apresenta as vantgens de ....

Foi apresentado um exemplo da utilização do protomake para uma aplicação simples de um servidor echo que cifra as mesnagens anstes de devolve-las a sua origem. A definição do protocolo é enxuta e etc etc. Torna-se aparente a vantagem da utilização do protomake, uma vez que o desenvolvimento deste protocolo em uma linguagem de programação é lento e sujeito a falhas (de implementação). O código-fonte de tal implementação seria várias vezes maior do que a sua descrição para o protomake.

Como trabalhos para aprimorar o protomake será desenvolida uma etc etc. Além disso, bla, bla, bla.

Referências

MCGUIRE, Tommy Marcus. Correct Implementation of Network Protocols from Abstract Specifications. February 15, 1994.

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

UML essencial: um breve guia para a linguagem-padrão de modelagem de objetos. Porto Alegre, Bookman, 2000.

MARC 21: Formato condensado para dados bibliográficos. Marília, UNESP - Marília Publicações, 2000

RAYMOND, Eric Stefen. The Cathedral and the Bazaar. http://www.tuxedo.org/~esr/writings/cathedral-bazaar/

Cesar Brod

2002-02-26T16:13:42

Cesar Brod