segunda-feira, março 16, 2009

O Protocolo XModem

O protocolo XModem é o pai de uma série de protocolos de transferência de arquivos que foram muito populares nos tempos da comunicação "banda magra" e que ainda são usados em dispositivos embarcados.

Já falei um pouco sobre ele antes (aqui e aqui) mas desta vez vou entrar em um pouco mais de detalhes.

A Vida On-Line Antes da Internet

A comunicação entre computadores via linha discada é algo bastante antigo. No mundo dos computadores pessoais, em 1978 (pouco depois do surgimento dos primeiros micros e muito antes de Tim Berners-Lee inventar a World Wide Web), Ward Christensen estabeleceu a primeira BBS.

Nos anos 80 um acessório cool era o modem. Inicialmente uma caixa externa e posteriormente uma placa de expansão, os modems da época permitiam comunicar via linha telefônica a velocidades como 300, 1200 e (mais tarde) 2400 bps (o que corresponde respectivamente a 30, 120 e 240 bytes por segundo).

Placa Listic TD1222/BV: 300, 1200, 1275 e 2400 bps!

As conexões eram bastante precárias. Não era incomum precisar algumas tentativas para os modems das duas pontas se entenderem. Conseguida a conexão, eram comuns três tipos de ocorrência:
  • a "geração espontânea" de caracteres, quando ruídos da linha eram errôneamente decodificados pelo modem;
  • o "sumiço" de caracteres, quando a comunicação entre as pontas era momentaneamente perdida; e
  • a alteração de caracteres em outros, devido à distorção do sinal.
E é claro que ocorriam também desconexões inesperadas.

O Protocolo XModem

Nas palavras de seu criador, o protocolo XModem surgiu de forma não planejada, para resolver um problema imediato de transferência de arquivos:

"It was a quick hack I threw together, very unplanned (like everything I do), to satisfy a personal need to communicate with 'some other' people"

O protocolo XModem supõe que exista um canal transparente entre os dois computadores, que permita o tráfego de qualquer byte de 0x00 a 0xFF. Alguns caracteres são utilizados pelo protocolo porém podem estar presentes dentro dos dados transferidos (o que é uma das vulnerabilidades do protocolo):

SOH 0x01
EOT 0x04
ACK 0x06
NAK 0x15

Na transferência de dados é utilizado um pacote com tamanho fixo de 132 bytes

onde
  • SOH (0x01) indica o início do pacote
  • PAC é o número do pacote. Este número começa com 1 e é incrementado a cada pacote. Após o pacotes 255 segue o pacote 0 (ou seja, o número do pacote é um byte que é incrementado ignorando o overflow);
  • ~PAC é o complemento de um do número do pacote. Pode ser calculado como 255-PAC ou invertendo cada bit
  • Dados são os dados transferidos, com tamanho fixo de 128 bytes.
  • CHK é o checksum, calculado somando todos os bytes de dados igonorando o overflow.
A dinâmica de comunicação é bastantes simples:
  • O receptor envia periodicamente NAK para indicar ao transmissor que está pronto para receber (isto permite disparar as pontas em qualquer ordem).
  • Ao escutar o NAK, o transmissor envia o primeiro pacote (de número 1)
  • Ao receber com sucesso um pacote, o receptor envia ACK. Se o pacote foi recebido incorretamente, envia NAK
  • Ao receber NAK o transmissor deve retransmitir o último pacote. Ao receber ACK o transmissor incrementa o número do pacote e envia o pacote seguinte (se existir)
  • Ao receber ACK do último pacotes, o transmissor envia EOT. O receptor deve confirmar o recebimento do EOT através de ACK.
A figura abaixo mostra esta dinâmica.


Considerações do Transmissor

O transmissor é bastante simples. O pacote a transmitir deve ser preferialmente montado antes do inicio da sua transmissão, para evitar pausas no meio da transmissão do pacote. Os momentos adequados para montar um pacote é no início da comunicação e após receber o ACK de um pacote. Antes de enviar o pacote (ou melhor ainda, antes de enviar o último caracter do pacote) o transmissor deve limpar a sua fila de recepção para diminuir a possibilidade de "lixo" ser interpretado como a resposta do receptor.

Embora costumeiramente o transmissor costume dar um timeout na resposta do receptor, isto não é obrigatório. Os timeouts no receptor são suficiente para recuperar as situações de erro.

Considerações do Receptor

Logo antes de enviar uma resposta o receptor deve limpar a sua fila de recepção, para diminuir a possibilidade de "lixo" ser interpretado. Na recepção do pacote, deve ignorar caracteres até receber a marca de início (SOH), dando timeout caso a marca não seja recebida dentro de um certo tempo. A partir deste ponto deve aguardar todos os caracteres do pacote, dando timeout caso o caracter seguinte não seja recebido dentro de 1 segundo. Em todos os casos de timeout o receptor deve enviar NAK.

Recebido um pacote, deve ser verificada a sua consistência, conferindo o número do pacote com seu complemento e o checksum dos dados. Se o pacote não estiver íntegro, o receptor deve enviar NAK.

Recebido um pacote íntegro, o receptor deve examinar o número do pacote:
  • Se for o pacote esperado, gravar os dados, incrementar o número do pacote esperado e enviar ACK.
  • Se for o pacote anterior ao esperado, enviar ACK. Isto ocorre se um ACK anterior foi extraviado ou danificado, causando a retransmissão do pacote.
  • Se for um pacote diferente do esperado ou o anterior, abortar a transferência. O transmissor e receptor perderam o sincronismo na numeração dos pacotes, possivelmente pelo transmissor achar que recebeu o ACK de um pacote que não foi recebido corretamente.
Concluindo

O protocolo XModem "básico" que foi apresentado é suficiente para muitas aplicações, principalmente as que envolvem conexões com baixas taxa de erro e volumes não elevados de dados. Ele possui, entretanto, algumas limitações. No próximo post da série vamos ver alguns aperfeiçoamentos populares para o XModem.

Referência

XMODEM/YMODEM PROTOCOL REFERENCE
- Edited by Chuck Forsberg

Um comentário:

Anônimo disse...

muito obrigado