Giter Site home page Giter Site logo

rcom's Introduction

🐧 Check Wiki For Lab Guides 🐧

FEUP - RCOM

Redes de Computadores

Course Page

Este repositório contém:

Grades

Média TPC Lab1 Lab2 Frequência Exame Final
16.0 19.0 18.0 18.0 ? 15

rcom's People

Contributors

ca-moes avatar filiperecharte avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

anasofia2407

rcom's Issues

Testes nos pc's da FEUP

  • Retirar todos os tcflush (desnecessários)
  • adicionar perror("read failed") antes de switch quando res==-1 só em reading e writing cycle
  • pôr perror's a vermelho

  • alterar valores de V_TIME e V_MIN

Emissor a não receber Resposta

Problema: Quando BCC2 era 0x7e o Emissor não recebia uma trama de confirmação, mas a seguir reenviava e recebia bem, fechando bem o programa e enviando bem o ficheiro

Solução:
unsigned char finalBuffer[currentLenght +6]; /trama I completa/
passou para
unsigned char finalBuffer[currentLenght + 4 + buf2Size]; /trama I completa/

Read aberto apenas

Caso apenas o read esteja aberto, podemos instalar um handler e um alarm no inicio para que caso não se estabeleça nenhuma ligação em X segundos, llopen retorna -1.

Programas Escritor e Leitor separados a usar llopen()

Criar 2 programas reader.c writer.c que no futuro serão apenas um chamado app.c e que receberá um argumento na execução.

Estes programas têm de usar a função llopen() e conseguir estabelecer uma ligação, ainda sem enviar dados.

Não esquecer de usar as funções de log para mostrar na consola os passos do programa.

Avaliar Performance

FER - Frame Error Rate
T_prop - Tempo de Propagação
C - capacidade ligação
I Size - MAX_SIZE

image

byte stuffing ultrapassa MAX_SIZE

Estamos a passar um buffer com MAX_SIZE ao llwrite mas esse buffer pode precisar de stuffing e não estamos a ter isso em conta, assim vai ultrapassar o MAX_SIZE e dar merda no frame buffer da linkLayer (é este o problema do frame e não o padding).

Temos de arranjar maneira de gerir o tamanho depois de o frame ter levado com byte stuffing.

Aqui o lenght é realmente igual a MAX_SIZE:

int llwrite(int fd, char *buffer, int lenght){
int currentLenght = lenght;
unsigned char buf1[4] = {FLAG, A_ER, C_I(linkLayer.sequenceNumber), BCC(A_ER, C_I(linkLayer.sequenceNumber))};
unsigned char *dataBuffer = (unsigned char *)malloc(lenght);
  
if (lenght > MAX_SIZE){
    log_error("llwrite() - Message size greater than MAX_SIZE");
    return -1;
  }

faz-se byte stuffing

e aqui o finalBuffer já pode ter um tamanho bem maior dependendo dos stuffings q levou:

unsigned char finalBuffer[currentLenght + 6]; /*trama I completa*/
fillFinalBuffer(finalBuffer, buf1, buf2, dataBuffer, currentLenght);
stateMachineSetUp(C_RR(linkLayer.sequenceNumber^0x01), A_ER, Start, Write);
writeCycle(writeR, fd, finalBuffer, sizeof(finalBuffer));

Por isso é que dá merda no pinguim.gif e nos ficheiros de texto não, porque precisa de muitos mais stuffings que o ficheiro de texto e origina mais leaks de memória.

A minha sugestão seria ter um MAX_SIZE -> que seria o tamanho máximo sem stuffing.
e depois ter outro MAX_SIZE_AFTER_STUFFING -> que seria o tamanho máximo possível do frame após o stuffing ou seja MAX_SIZE * 2.
Não sei se é a melhor solução mas penso que resolve

Lab1 - Aula 3

A fazer na sala:

  • Com programa de teste dos pc's verificar que existe ligação
  • Testar programa 2 (write/read SET/UA)

ToDo:

  • Testar timeout do emissor:
    • Com Receptor desligado, ligar emissor e esperar que ele mande mensagem N vezes (verificar com prints)
  • formar camadas: API e Aplicação -> llopen()
  • ter a abrir ligação dos dois lados
  • llwrite() -> formar tramas e enviar, esperar confirmação da boa receção da trama
    • retorna quando envia com sucesso
  • llread() -> receber, verificar erros e confirmar receção
    • retorna

Info

I : [F, A, C, BCC1, D1, D2, ..., Dn, BCC2, F]

  • FLAG - flag - 01111110 (0x7E)
    • Mecanismo de receção tem de verificar se a trama tem as flags corretas
  • A - Campo de Endereço
    • 00000011 (0x03) em Comandos enviados pelo Emissor e Respostas enviadas pelo Receptor
    • 00000001 (0x01) em Comandos enviados pelo Receptor e Respostas enviadas pelo Emissor
  • C - Campo de Controlo

Lab1 - Aula 2

SET = [FLAG,A,C,BCC,FLAG]
UA = [FLAG,A,C,BCC,FLAG]

  • FLAG - flag - 01111110 (0x7E)
    • Mecanismo de receção tem de verificar se a trama tem as flags corretas
  • A - Campo de Endereço
    • 00000011 (0x03) em Comandos enviados pelo Emissor e Respostas enviadas pelo Receptor
    • 00000001 (0x01) em Comandos enviados pelo Receptor e Respostas enviadas pelo Emissor
  • C - Campo de Controlo
    • SET (set up) - 0 0 0 0 0 0 1 1 (0x03)
    • UA (unnumbered acknowledgment) - 0 0 0 0 0 1 1 1 (0x07)
  • BCC1 - XOR entre A e C para verificação

Verificar numero de Sequência

Na application layer quando se recebe um numero de sequência que não é suposto, deve fazer-se lseek() para ir à posição certa do ficheiro escrever esse conjunto de dados.

Refactoring de PLA

Esboços de Ideia

De acordo com #17 e #18 estes ciclos são muito usados ao longo do pla e podem ser extraidos Para deixar o código mais limpo.

Também estive a pensar em usar algo como o que fizemos para LPOO relativo aos estados do PLA:

  • Ter só uma máquina de estados que será usada por todas as funções do pla (llopen() llwrite() llread() llclose()) -> Que é como temos agora, já que estamos a usar o mesmo enum para ambas as máquina de estados.
  • Ao processar um byte mandar uma struct como argumento com o byte e mais variaveis de info (Byte de Controlo esperado, Byte de Adress esperado),

Código repetido de state machine

Objetivo : Ter só uma máquina de estados personalizável que processe todo o tipo de tramas

Para ficar bem organizado seria criado um ficheiro só para conteúdo relativo á maquina de estados : state_machine.c
No inicio de cada função da pla dar setup á máquina de estados modificando a struct.
Ter uma struct global do estado da máquina de estados com

  • Control Byte Esperado
  • Address Byte Esperado
  • Enum com type de máquina de estados (Supervision, Read, Write)

No inicio de cada função do pla ficaria algo do gênero:

state_machine.mode = Supervision;
state_machine.control = C_UA;
state_machine.adress = A_ER;

e chama-se dentro dos ciclos de leitura a máquina com:

stateMachine(byte, null, null);  // para outros casos
// OU
stateMachine(byte, &buf, &size);  // para o caso de Read

Na função de state machine teremos as variaveis estáticas (que poderão ser globais) e um switch:

stateMachine(unsigned char byte, unsigned char **buf, int* bufsize){
   static unsigned char checkBuffer[2];
   static int frameIndex, wrongC;
   switch(state){  // Start, FLAG_RCV ...
      case Start:
         ProcessStart(Byte);
      break;
}

Cada Case apontará para um função que terá dentro um switch ou if..else para cada state_machine.mode:

ProcessStart(unsigned char byte){
  switch(state_machine.mode)
    case supervision:
    break;
    case read:
    break;
}

Possível que dê merdinha ao passar o pointer pointer da buffer da máquina de estados do read. Mas deve se arranjar solução

Código repetido dos ciclos de leitura

Objetivo : Ter duas funções, cada uma representa um dos issues (#17 e #18) para serem usadas nas funções do pla.

Daqui é possível criar duas funções, uma para cada issue e passar todos os argumentos necessários, se possivel dentro de uma struct se os argumentos forem comuns para simplificar.

MAKEFILE

Pôr o makefile a funcionar. É com isto que se compila de acordo com o relatório

Potencial Problema

Na leitura, caso haja um erro nos bytes de cabeçalho é cancelada a leitura e mandado um REJ ou RR (caso sequence number esteja trocado).
Não tenha a certeza ao que acontece ao resto dos bytes que estão na trama. Se eles ficarem no buffer para ler então será preciso que a read leia tudo e no fim é que mande o RR ou REJ para limpar o buffer de leitura

Improve performance

Nós fazemos o BCC2 e depois damos stuffing, já que o BCC é sem dar stuff, secalhar conseguimos juntar estes 2 loops para fazer o bcc2 e o stuffing ao mesmo tempo.

 /*building trama I*/
  unsigned char BCC2 = buffer[0];
  for (int i = 1; i<lenght; i++){
    BCC2 = BCC2 ^ buffer[i];
  }

// Byte Stuffing (data buffer)
  for (int i = 0, k=0; i<lenght; i++, k++){
    if (buffer[i] == 0x7E || buffer[i] == 0x7D){
      currentLenght++;
      dataBuffer = (unsigned char *) realloc(dataBuffer, currentLenght); 

      dataBuffer[k+1] = buffer[i] ^ 0x20;
      dataBuffer[k] = 0x7D;
      k++;
    }
    else{
      dataBuffer[k] = buffer[i];
    }
  }

Iniciar llwrite()

O programa terá 2 passos:

  1. Criar a trama I
  2. Escrever a trama I

Para criar a Trama I (passo 1) terá de recolher os seguintes valores:

  • Flag1
    • 0x7e
  • Adress
    • 0x03
  • Control Byte
    • checkar guião
  • BCC 1
    • XOR entre A e C
  • BCC 2
    • XOR dos bytes de Dados antes de stuffing
  • Flag2
    • 0x7e

Após ter estes valores guardados podemos começar o stuffing :

For byte in buffer_dados:
   if byte == 0x7E
      byte = 0x7D 0x5E
   if byte == 0x7D
      byte = 0x7D 0x5D

criando assim o array de Dados, espeta-se isso no meio da trama e tá pronto para mandar

Organizar MACROS

unsigned int timeout; /Alarm Timeout: x s/
unsigned int numTransmissions; /Number of tries in case of failure/

strcpy(linkLayer.port,port);
linkLayer.baudRate = BAUDRATE;
linkLayer.sequenceNumber = 0x00;
linkLayer.timeout = 3;
linkLayer.numTransmissions = 3;

Coisas que acontecem

O transmitter manda um frame (113) ao qual o o receiver responde enviando um RR, esse RR não chega ao Transmitter apesar de ser enviado pelo Receiver (bytes sent: 5).
O que faz com que o Transmitter reenvie o mesmo frame (que agora é o 114) mas acontece que o programa verifica que o Control Byte não é igual ao C_I(sequenceNumber_expected) sendo um frame duplicado, envia um RR e passa ao próximo.

Receiver:
1

Transmitter:
2

Enum State

A variável que contem o enum state é global mas ao passar para a máquina de estados está a ser passada por referência &state.
Ou pomos um enum em cada função e passamos por ref ou pomos o enum global e não se passa sequer como argumento da máquina de estados, já que esta tem acesso global.

Duas flags 0x7e no final de uma trama I a enviar

Ao enviar tramas I aconteceu que mandava 2 vezes a flag de final.

Problema: BCC2 estava a ficar com o valor 7e e o BCC2 não estava a levar stuffing

Solução: Dar stuffing ao BCC2

--
Poderá o mesmo acontecer a BCC1?

#define A_ER                  0b00000011  ///< (0x03) Campo de Endereço (A) de commandos do Emissor, resposta do Receptor
#define A_RE                  0b00000001  ///< (0x01) Campo de Endereço (A) de commandos do Receptor, resposta do Emissor

#define C_SET                 0b00000011 ///< (0x03) Campo de Controlo - SET (set up)
#define C_DISC                0b00001011 ///< (0x0B) Campo de Controlo - DISC (disconnect)
#define C_UA                  0b00000111 ///< (0x07) Campo de Controlo - UA (Unnumbered Acknowledgement)
#define C_RR(r)               ((0b00000101) ^ (r) << (7)) ///< (0x05 OU 0x85) Campo de Controlo - RR (receiver ready / positive ACK))
#define C_REJ(r)              ((0b00000001) ^ (r) << (7)) ///< (0x01 OU 0x81) Campo de Controlo - REJ (reject / negative ACK))
#define C_I(r)                ((0b01000000) & (r) << (6)) ///< (0x00 0x40) Campo de Controlo - Tramas I 


A_ER ^ C_SET = 0x00
A_ER ^ C_DISC = 0x08
A_ER ^ C_UA = 0x04
A_ER ^ C_RR 1 = 0x86
A_ER ^ C_RR 0 = 0x06
A_ER ^ C_REJ 1 = 0x82
A_ER ^ C_REJ 0 = 0x02
A_ER ^ C_I 1 = 0x43
A_ER ^ C_I 0 = 0x03

A_RE ^ C_SET = 0x02
A_RE ^ C_DISC = 0x0a
A_RE ^ C_UA = 0x06
A_RE ^ C_RR 1 = 0x84
A_RE ^ C_RR 0 = 0x04
A_RE ^ C_REJ 1 = 0x80
A_RE ^ C_REJ 0 = 0x00
A_RE ^ C_I 1 = 0x41
A_RE ^ C_I 0 = 0x01

Resposta: não

Refactor de do_while() para escrever

Na função transmitter_set e em llwrite() o do_while() é muito igual, muda os log();
dá para pôr isso numa função void cujo argumento diz quais as mensagens logs a mandar

image

Byte a mais

Connection established.
Content: 0x7e
Content: 0x03
Content: 0x40
Content: 0x43
cut
Content: 0x7e
Content: 0x03
Content: 0x40
Content: 0x43
Content: 0x04
Content: 0x68
Content: 0x65
Content: 0x6c
Content: 0x7d
Content: 0x5e
Content: 0x6f
Content: 0x70

Byte 0x04 está a ser inserido entre BCC1 e Dados

Emissor bloqueado no Read

Parece que após sair do signal handler o read continua blockeado


Se/quando corrigirmos isto podemos deixar estar a pasta Aula 2 como está e criar uma nova pasta para fazer o resto da primeira prática laboratorial

Verificar mensagens de erro

Algumas mensagens de erro estão erradas (nome da função de onde são chamadas errado).
Temos de verificar 1 a 1 os returns -1 a ver se têm um log_error direito

BCC_OK State no llread a causar estragos no llclose()

Basicamente tentei enviar o pinguim.gif, e ele não consegue fechar tudo direito.

Fiz debug e o que está a acontecer é:
Por alguma razão a variavel frame unsigned char frame[MAX_SIZE+6]; /*Trama*/ na struct linkLayer está a ficar sem espaço e está a afetar a variável unsigned int status; /*TRANSMITTER | RECEIVER*/ fazendo com que ela fique com lixo.

variavel status da struct linklayer:
"STATUSS" antes de correr a máquina de estados e "status2" depois de correr a maquina de estados:
Screenshot from 2020-10-25 02-54-09
o que faz com que o receiver chegue ao fim e não corra o llclose :-)

Isto acontece ao preencher o frame na maquina de estados do llread:
if (state_machine.type == Read) linkLayer.frame[frameIndex] = byte;
E acontece logo com o primeiro frame.

a 7 bytes do fim da trama I, ou seja se adicionarmos 7 ao tamanho do frame buffer corre tudo muito bem - temos de descobrir pq é q ele está a usar mais 7bytes do que é suposto

O pior é que só acontece com este ficheiro, experimentei com um ficheiro de texto com bué caracteres e funcionou bem. lets see

A corrigir em Download

Situações em que o programa fica bloqueado em vez de terminar:

  • ao ligar a netlab sem VPN fica bloqueado em vez de fechar
    • caso a VPN não esteja ligada, o programa fica bloqueado em gethostbyname, já que o DNS não tem o endereço IP do que se quer aceder. Não há uma forma fácil de tratar disto sem misturar forks e processos filhos, por isso ficou um print por cima da chamada gethostbyname e por baixo para saber se está bloqueado nessa secção.
    • Correção, demora mas acaba por dar erro e terminar.
  • ao dar um path para um ficheiro que não existe fica bloqueado
  • login errado

Alarm a receber UA no llclose com valor relativo

stateMachineSetUp(C_UA, A_RE, Start, Supervision);

  alarm(5); /* waits a limited time for UA response from Transmitter */
  /* parse UA*/
  if (readingCycle(closeDISC, fd, NULL, NULL, NULL) < 0)
    return -1;
  
  alarm(0);
  return fd;

Receiver_DISC_UA na receção do UA

Adicionar Funções log

Aproveitar de LAIG e SOPE. Podemos acrescentar umas funções que mandem diferentes mensagens:

  • Mensagens de Log
  • Mensagens de Erro
  • Mensagens de Caution

Separar pld.c e pld_spec.c

pld.c e pld.h terão as funções llopen() llwrite() llread() llclose()
pld_spec.c e pld_spec.h (pld specification) terão o resto das funções

Salas RCOM - Leitura Errada

Ao ler nos pc's em RCOM a leitura pela parte do emissor está mal. O Emissor lê lixo enquanto que no socat funcionar bem

Solução : Trocar os buffers de char[] para unsigned char[]

llopen()

o writenoncanonical.c e noncanonical.c passarão a ser a função llopen(int porta, flag TRANSMITTER | RECEIVER) num novo ficheiro pld.c Protocolo de Ligação de Dados.

image

Ao dar sucesso vai devolver o fd que arranja no inicio fd = open(argv[1], O_RDWR | O_NOCTTY );
Not sure se o que manda como primeiro argumento - int porta é suposto ser o /dev/ttySx

llclose() - máquina de estados

image

DISC (disconnect) 00001011 - 0x08
UA (unnumbered acknowledgment) - 00000111 - 0x07

Modificar stateMachine_SET_UA para receber um enum {SET, UA, DISC} em vez de int type e com isso verifica dentro da state Machine qual é o C que é suposto receber.

A struct que está nos slides:

struct applicationLayer {
    int filedescriptor;   /*Descritor correspondente à porta série*/
    int status            /*TRANSMITTER | RECEIVER*/
}

Daria jeito aqui porque o llclose() é diferente para o receiver e transmitter e pelos slides int llclose(int fd) não recebe como argumento o type como o int llopen(int porta, TRANSMITTER | RECEIVER)
Tendo a struct como global esta poderia ser acedida pelo llclose() para saber como fechar.
Com isto llclose fica assim:

  • Transmitter:
    • ciclo do...while com while dentro para mandar DISC e esperar DISC. Ter alarm para caso receba mal ou não receba mande outra vez
    • Mandar UA e fechar (tal como receiver em llopen() manda UA e retorna)
unsigned char replyBuf[UA_SIZE] = {FLAG, A_ER, C_UA, BCC(A_ER, C_UA), FLAG};
res = write(fd,replyBuf,UA_SIZE); //+1 para enviar o \0 
if (res == -1) {
  log_error("receiver_UA() - Failed writing UA to buffer.");
  return -1;
}
return 0;
  • Receiver
    • ciclo while para ler DISC até estado estar Done
    • ciclo do...while com while dentro para mandar DISC e esperar UA. Ter alarm para caso receba mal ou não receba mande outra vez

Guiões na Tab Wiki

Para manter a organização os guiões das experiências passaram para a tab Wiki

image

Passa por lá

Aplicação

Aplicação

Do lado do Transmissor terá de ser possível passar como argumento o nome do ficheiro a transferir, numa primeira fase o ficheiro estará no diretório do código source, mais tarde podemos aceitar paths absolutos.
Do lado do Recetor podemos também numa fase avançada passar por argumento o caminho onde ficará o ficheiro.

Após a leitura dos argumentos este será o flow do programa:

image

Ambas as partes executarão llopen() para estabelecer a ligação. Caso o Emissor não consiga fazer llopen() a função retorna -1 e o programa pode fechar. Do lado do Recetor fica aberto ou fecha após x segundos [refer to #19].

Assim que se estabelecer uma ligação o Emissor cria o Pacote de Controlo para dar informação sobre o inicio da transferência de dados:

image

e pode dar um llwrite(Cp); (Cp = Control Packet).
Do lado do Recetor teremos um llread(Cp) que assim que leia com sucesso dará parse de toda a informação.

IMPORTANTE dar parse da informação relativa ao tamanho em bytes do ficheiro para conseguir controlar a leitura.

Aqui o Emissor pode começar a mandar Pacotes de Dados:

image

Constrói o pacote, mandando para llwrite() o buffer e o tamanho em bytes. Como llwrite() pode dar erro e devolver -1 este terá de estar envolvido num do...while para fazer várias tentativas de envio. Caso não consiga enviar um pacote de dados ao fim de x tentativas algo aconteceu á ligação, com isto o programa apresenta uma mensagem de erro e dá return.

Do lado do Recetor teremos um ciclo while(1) que estará constantemente a ler e levará break em certas situações. Este ciclo servirá para ler todos os pacotes até receber o último pacote: Um Pacote de Controlo para sinalizar o fim da transferência.
Dentro do ciclo teremos um llread(buffer) para receber os Pacotes de Dados e uma função para dar parse da informação recebida. No meio da informação teremos o tamanho em bytes do campo de dados e podemos ir subtraindo este valor ao tamanho total do ficheiro para sabermos quando perto do fim da transferência estamos.

Após mandar todos os Pacotes de Dados, o Emissor cria o pacote de Controlo para finalizar a transmissão e manda via llwrite(Cp). Após isto pode iniciar a sequência de fecho do pla com llclose().

Do lado do Recetor vamos receber no ciclo de leitura dos Pacotes de Dados o Pacote de Controlo de fecho, saindo assim do ciclo e iniciando também a sequência de fecho do pla com llclose().

Verificação de Erros

Da forma como a Link Layer está feita não haverá erros na transmissão da informação dos dados já que o recetor verifica isso e caso haja erros (BCC errado) pede um reenvio. Mesmo assim é possivel que llwrite() retorne -1, neste caso o Emissor terá de tentar mais vezes com llwrite() e verificar se o problema persiste, em caso positivo fecha a aplicação com mensagem de erro.

image

Buffers OR Structs

Temos a possibilidade de trocar no programa writenoncanonical.c o buffer de unsigned char para uma struct com os valores de cada Byte. Em termos de organização de dados seria preferivel mas surgem daqui umas questões a considerar, nomeadamente padding:

image

Se cada elemento da struct fosse um unsigned char não haveria problemas. Não seria necessário padding e sizeof seria n_elementos * 1 (tamanho em bytes)

Mas como a trama de Informação terá um campo de dados que será variável terá de ser um unsigned char[] dentro da struct, que com o padding iria aumentar o tamanho da struct apresentado pelo sizeof

Isto não foi ainda testado. Pode ocorrer de que o array é divido também em camadas. Por enquanto não tenho a certeza


Sources

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.