Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
1 result

messages.cpp

Blame
  • messages.cpp 22.54 KiB
    // Implementado por: Eduardo Machado e Victor Perszel
    // 2015
    
    #include "messages.h"
    
    //######################### MÉTODOS DA CLASSE Message #########################
    
    int Message::sendCD(unsigned char* dirName){
      int error, success = 0, garbage, rv;
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      struct pollfd ufds[1]; // usado para timeout em recv
      SubMessage changeDir, answer;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      changeDir.setData(dirName,3,0);
    
      while(!success){
        error = send(soquete, changeDir.objToString(), changeDir.getSize()+4, 0);
        if (error == -1){
          cout << "Erro ao tentar mudar de diretório (messages.cpp::sendCD)" << endl;
        }
    
        garbage = 0;
        while((garbage < 10) && (!success)){
          // vetor de pollfd, numero de buffers observados, timeout(ms)
          rv = poll(ufds, 1, 500);
          if(rv){
            if(rv == -1){
              cout << "Erro no recebimento de resposta (messages.cpp::sendCD)" << endl;
              return -1;
            } else {
              recv(soquete, receiptMessage, 68*sizeof(char), 0);
              answer.stringToObj((unsigned char*)receiptMessage);
              // Lê começo da mensagem e vê se tem o delimitador de início
              if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                success = 1;
                if(answer.getType() == 8){ // 8 = OK
                  // Tá ok para mudar de Diretório
                  return 0; // YAY
                } else if(answer.getType() == 0){ // 0 = NACK
                  // NACK
                  success = 0; // reenvia pedido
                } else if(answer.getType() == 14){ //14 = 0xE --> Erro
                  // ERRO
                  if(answer.getData()[0] == '0'){
                    cout << "Diretório Inexistente\n" << endl;
                    return -1;
                  } else if (answer.getData()[0] == '1'){
                    cout << "Sem permissão para acessar o diretório\n" << endl;
                    return -1;
                  } else {
                    success = 0; // reenvia pedido
                  }
                }
              }
            }
          } else{
            cout << "Tempo limite de resposta excedido :c\n" << endl;
            cout << "TIMEOUT ATINGIDO (messages.cpp::sendData)" << endl;
          }
          garbage++;
        }
      }
    }
    
    int Message::sendLS(unsigned char* options){
      int error, success = 0, garbage, rv;
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      struct pollfd ufds[1]; // usado para timeout em recv
      char* listagem;
      SubMessage listDir, answer, ack, nack;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      listDir.setData(options,4,0);
    
      while(!success){
        error = send(soquete, listDir.objToString(), listDir.getSize()+4, 0);
        if (error == -1){
          cout << "Erro ao tentar listar diretorio (messages.cpp::sendLS)" << endl;
        }
    
        garbage = 0;
        while((garbage < 10) && (!success)){
          // vetor de pollfd, numero de buffers observados, timeout(ms)
          rv = poll(ufds, 1, 500);
          if(rv){
            if(rv == -1){
              cout << "Erro no recebimento de resposta (messages.cpp::sendLS)" << endl;
              return -1;
            } else {
              recv(soquete, receiptMessage, 68*sizeof(char), 0);
              answer.stringToObj((unsigned char*)receiptMessage);
              // Lê começo da mensagem e vê se tem o delimitador de início
              if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                success = 1;
                if(answer.getType() == 10){ // 10 = 0xA --> (A)mostra
                  // Mostra as mensagens
                  if(answer.checkParity()){ // Caso a paridade dê errado
                    nack.setData((unsigned char*)answer.getSeq(),0,0); // Manda um nack
                    send(soquete,nack.objToString(),nack.getSize()+4, 0);
                    success = 0;
                  } else {
                    strcat(listagem,(char*)answer.getData()); // Põe o valor recebido em "listagem"
                    success = 0;
                    while(!success){
                      rv = poll(ufds, 1, 500); // Observa por novas mensagens
                      if(rv){
                        recv(soquete, receiptMessage, 68*sizeof(char), 0);
                        answer.stringToObj((unsigned char*)receiptMessage);
                        if(answer.getStartMessage() == 0x7E){
                          if(answer.getType() == 10){ // 10 = 0xA --> (A)mostra
                            if(answer.checkParity()){ // Caso a paridade dê errado
                              nack.setData((unsigned char*)answer.getSeq(),0,0); // Manda um nack
                              send(soquete,nack.objToString(),nack.getSize()+4, 0);
                              success = 0;
                            } else {
                              strcat(listagem,(char*)answer.getData()); // Põe em "listagem"
                              ack.setData((unsigned char*)answer.getSeq(),1,0);
                              send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                            }
                          } else if (answer.getType() == 15) { // Se for FIM
                            ack.setData((unsigned char*)answer.getSeq(),1,0);
                            success = 1;
                          }
                        }
                      } else {
                        cout << "TIMEOUT DO LS (messages.cpp::sendLS)" << endl;
                      }
                    }
                  }
                  cout << listagem << endl;
                  return 0; // YAY
                } else if(answer.getType() == 0){ // 0 = NACK
                  // NACK
                  success = 0; // reenvia pedido
                } else if(answer.getType() == 14){ //14 = 0xE --> Erro
                  // ERRO
                  if(answer.getData()[0] == '0'){
                    cout << "Opção inválida, por favor tente -l, -a ou -la\n" << endl;
                    return -1;
                  } else {
                    success = 0; // reenvia pedido
                  }
                }
              }
            }
          } else{
            cout << "Tempo limite de resposta excedido :c\n" << endl;
            cout << "TIMEOUT ATINGIDO (messages.cpp::sendData)" << endl;
          }
          garbage++;
        }
      }
    }
    
    int Message::sendPUT(unsigned char* fileName){
      int error, success = 0, garbage, rv;
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      string temp, fileData;
      struct pollfd ufds[1]; // usado para timeout em recv
      SubMessage put, answer, size;
      ifstream fileIn;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      put.setData(fileName,5,0);
    
      fileIn.open((char*)fileName, ios::in);
      fileIn.seekg(0);
    
      while(getline(fileIn, temp)) {
        fileData += temp + "\n";
      }
    
      while(!success){
        error = send(soquete, put.objToString(), put.getSize()+4, 0);
        if (error == -1){
          cout << "Erro ao enviar arquivo (messages.cpp::sendPUT)" << endl;
        }
    
        garbage = 0;
        while((garbage < 10) && (!success)){
          // vetor de pollfd, numero de buffers observados, timeout(ms)
          rv = poll(ufds, 1, 500);
          if(rv){
            if(rv == -1){
              cout << "Erro no recebimento de resposta (messages.cpp::sendPUT)" << endl;
              return -1;
            } else {
              recv(soquete, receiptMessage, 68*sizeof(char), 0);
              answer.stringToObj((unsigned char*)receiptMessage);
              // Lê começo da mensagem e vê se tem o delimitador de início
              if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                success = 1;
                if(answer.getType() == 8){ // 8 = OK
                  // OK, mandar tamanho
                  size.setData((unsigned char*)fileData.size(),9,0);
                  send(soquete, size.objToString(), size.getSize()+4, 0);
                  success = 0;
                  while(!success){
                    rv = poll(ufds, 1, 500);
                    if (rv){
                      if(rv == -1){
                        cout << "Erro no recebimento de resposta (messages.cpp::sendPUT)" << endl;
                        return -1;
                      } else {
                        recv(soquete, receiptMessage, 68*sizeof(char), 0);
                        answer.stringToObj((unsigned char*)receiptMessage);
                        if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                          if(answer.getType() == 8){
                            success = 1;
                            if(sendData((unsigned char*)fileData.c_str())){
                              cout << "Erro ao mandar dados (messages.cpp::sendPUT)" << endl;
                              return -1;
                            }
                          } else if (answer.getType() == 0){
                            success = 0;
                          } else if (answer.getType() == 15){ // 15 = 0xE --> Erro
                            if(answer.getData()[0] == '2'){
                              cout << "Não tem espaço para mandar o arquivo" << endl;
                              return -1;
                            } else {
                              success = 0;
                            }
                          }
                        }
                      }
                    }
                  }
                } else if(answer.getType() == 0){ // 0 = NACK
                  // NACK
                  success = 0; // reenvia pedido
                }
              }
            }
          } else{
            cout << "Tempo limite de resposta excedido :c\n" << endl;
            cout << "TIMEOUT ATINGIDO (messages.cpp::sendPUT)" << endl;
          }
          garbage++;
        }
      }
    }
    
    int Message::sendGET(unsigned char* fileName){
      int error, success = 0, garbage, rv;
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      string temp, fileData;
      struct pollfd ufds[1]; // usado para timeout em recv
      SubMessage get, answer, ack, nack, err, ok;
      ofstream fileOut;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      get.setData(fileName,6,0);
    
      while(!success){
        error = send(soquete, get.objToString(), get.getSize()+4, 0);
        if (error == -1){
          cout << "Erro ao receber arquivo (messages.cpp::sendGET)" << endl;
        }
    
        garbage = 0;
        while((garbage < 10) && (!success)){
          // vetor de pollfd, numero de buffers observados, timeout(ms)
          rv = poll(ufds, 1, 500);
          if(rv){
            if(rv == -1){
              cout << "Erro no recebimento de resposta (messages.cpp::sendGET)" << endl;
              return -1;
            } else {
              recv(soquete, receiptMessage, 68*sizeof(char), 0);
              answer.stringToObj((unsigned char*)receiptMessage);
              // Lê começo da mensagem e vê se tem o delimitador de início
              if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                if(answer.getType() == 0){
                  success = 0;
                } else if (answer.getType() == 15){ // Erro
                  if(answer.getData()[0] == '0'){
                    cout << "Arquivo Inexistente" << endl;
                    ack.setData((unsigned char*)answer.getSeq(),1,0);
                    send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                    return -1;
                  } else if (answer.getData()[0] == '1'){
                    cout << "Sem permissão para baixar o arquivo" << endl;
                    ack.setData((unsigned char*)answer.getSeq(),1,0);
                    send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                    return -1;
                  } else {
                    success = 0;
                  }
                } else if (answer.getType() == 9){ // Tamanho
                  if(testaSeTamanhoEhInvalido()){
                    err.setData((unsigned char*)answer.getSeq(),1,0);
                    send(soquete, err.objToString(), err.getSize()+4, 0); // Erro
                    return -1;
                  } else if(answer.checkParity()){
                    nack.setData((unsigned char*)answer.getSeq(),0,0); // Manda um nack
                    send(soquete,nack.objToString(),nack.getSize()+4, 0);
                    return -1;
                  } else {
                    ok.setData((unsigned char*)answer.getSeq(),8,0); // Manda um ok
                    send(soquete,ok.objToString(),ok.getSize()+4, 0);
                    if(receiveData(fileName,atoi((char*)answer.getData())) == -1){
                      cout << "Erro no recebimento de dados (messages.cpp::sendGET)" << endl;
                      return -1;
                    } else{
                      cout << "Arquivo transferido com sucesso" << endl;
                      return 0;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    
    int Message::sendData(unsigned char* stringMessage){
      int numberOfMessages, sizeLastMessage, size=0;
      int i, j, k, garbage, error, rv, success = 0;
      unsigned char* subData; // a parte da mensagem que vai em cada sequencia
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      char *erro1, *erro2, *sucesso, *buffer;
      struct pollfd ufds[1]; // usado para timeout em recv
      SubMessage answer, end;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      // Calcula o tamanho da msg
      while( stringMessage[size] != '\0'){
        size++;
      }
    
      // Verifica quantas mensagens serao necessarias
      if (size%64){
        numberOfMessages = (size/64) + 1;
      } else {
        numberOfMessages = (size/64);
      }
      sizeLastMessage = size%64;
      numberOfMessages++;  // +1 = Mensagem de FIM
    
      // Cria as sub mensagens
      SubMessage subMensagem[numberOfMessages];
    
      // string usada para dividir a mensagem de entrada e colocar na parte de data das SubMessages
      subData = (unsigned char*) malloc(sizeof(unsigned char) * 64);
    
      int tipo = 13; // 13 = 0xD --> Dados
    
      // Divide a mensagem
      k = 0; // k é a numero da sequencia na submensagem
      for(i = 0; i < numberOfMessages-1; ++i){
        for(j = 0; j < 64; ++j){
          subData[j] = stringMessage[(i*64)+j];
        }
        subMensagem[i].setData(subData, tipo, k);
        ++k;
        if(k == 64){ // Caso estoure o número de bits de sequencia
          k = 0;
        }
      }
      if (sizeLastMessage){
        // Caso a última mensagem não seja completa realoca subData para o tamanho da última mensagem
        subData = (unsigned char*) realloc(subData, sizeof(unsigned char) * sizeLastMessage);
        for(j = 0; j < sizeLastMessage; ++j){
          subData[j] = stringMessage[(i*64)+j];
        }
        subMensagem[i].setData(subData, tipo, k);
        ++k;
      }else{
        // Caso contrario continua com o tamanho maior
        for(j = 0; j < 64; ++j){
          subData[j] = stringMessage[(i*64)+j];
        }
        subMensagem[i].setData(subData, tipo, k);
        ++k;
      }
      // Seta mensagem de FIM
      i++;
      subMensagem[i].setData((unsigned char*)"FIM", 15, k); // Dados = "FIM", tipo = 0xF, sequencia = proxima
    
      // Caso haja só uma ou duas mensagens
      if (numberOfMessages < 4){
        while(!success){
          if(numberOfMessages < 1) {
            cout << "Algo parece estranho, sua mensagem contém conteúdo?\n" << endl;
            cout << "Erro: Mensagem nula (messages.cpp::sendData)" << endl;
            return -1;
          }
          // manda a primeira msg
          error = send(soquete, subMensagem[0].objToString() , subMensagem[i].getSize()+4, 0);
          if(numberOfMessages > 1) // Se forem 2 ou 3 msgs, manda a segunda
            error = send(soquete, subMensagem[1].objToString() , subMensagem[i].getSize()+4, 0);
          if(numberOfMessages > 2) // Se forem 3 msgs, manda a terceira
            error = send(soquete, subMensagem[2].objToString() , subMensagem[i].getSize()+4, 0);
    
          if(error == -1){
            cout << "Problema com o envio da mensagem (messages.cpp::sendData)" << endl;
          }
    
          // vetor de pollfd, numero de buffers observados, timeout(ms)
          rv = poll(ufds, 1, 500);
          if(rv){
            if(rv == -1){
              cout << "Erro no recebimento de resposta (messages.cpp::sendData)" << endl;
            } else {
              recv(soquete, receiptMessage, 68*sizeof(char), 0);
              answer.stringToObj((unsigned char*)receiptMessage);
              // Lê começo da mensagem e vê se tem o delimitador de início
              if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                if(numberOfMessages == 1){
                  if(answer.getType() == 1){ //ACK
                    success = 1; // YAY
                  } else {
                    cout << "Mensagem entregue com erro (messages.cpp::sendData)" << endl;
                  }
                } else if (numberOfMessages == 2){ // numero de mensagens = 2
                  if((answer.getType() == 1) && (answer.getData() == (unsigned char*)'1') ){ // aceitou ambas as msgs
                    success = 1; // YAY
                  } else {
                    cout << "Mensagem entregue com erro (messages.cpp::sendData)" << endl;
                  }
                } else { // numbero de mensagens = 3
                  if((answer.getType() == 1) && (answer.getData() == (unsigned char*)'2') ){ // aceitou ambas as msgs
                    success = 1; // YAY
                  } else {
                    cout << "Mensagem entregue com erro (messages.cpp::sendData)" << endl;
                  }
                }
              }
            }
          } else {
            cout << "Tempo limite de resposta excedido :c\n" << endl;
            cout << "TIMEOUT ATINGIDO (messages.cpp::sendData)" << endl;
          }
        }
        success = 0;
      } else if (numberOfMessages > 3){
        i = 0;
        while (i < numberOfMessages - 2){
          error = send(soquete, subMensagem[i].objToString() , subMensagem[i].getSize()+4, 0);
          if(i < numberOfMessages - 1)
            error = send(soquete, subMensagem[i+1].objToString() , subMensagem[i].getSize()+4, 0);
          if(i < numberOfMessages)
            error = send(soquete, subMensagem[i+2].objToString() , subMensagem[i].getSize()+4, 0);
    
          success = 0;
          garbage = 0;
          while((garbage < 10) && (!success)){ // Tenta 10 vezes para evitar reenviar a mensagem quando recebe lixo
            // vetor de pollfd, numero de buffers observados, timeout(ms)
            rv = poll(ufds, 1, 500);
            if(rv){
              if(rv == -1){
                cout << "Erro no recebimento de resposta (messages.cpp::sendData)" << endl;
                return -1;
              } else {
                recv(soquete, receiptMessage, 68*sizeof(char), 0);
                answer.stringToObj((unsigned char*)receiptMessage);
                // Lê começo da mensagem e vê se tem o delimitador de início
                if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
                  success = 1;
                  if(answer.getType() == 1) {
                    sprintf(erro1, "%d", i);
                    sprintf(erro2, "%d", i+1);
                    sprintf(sucesso, "%d", i+2);
                    if(answer.getData() == (unsigned char*)erro1){
                      i += 1;
                    } else if (answer.getData() == (unsigned char*)erro2){
                      i += 2;
                    } else if (answer.getData() == (unsigned char*)sucesso){
                      i += 3;
                    } else {
                      success = 0;
                    }
                  } else if (answer.getType() == 0){
                    success = 0; // NACK
                  }
                }
              }
            } else {
              cout << "Tempo limite de resposta excedido :c\n" << endl;
              cout << "TIMEOUT ATINGIDO (messages.cpp::sendData)" << endl;
            }
            garbage++;
          }
        }
      }
      return 0;
    }
    
    //################# MÉTODOS DA CLASSE Message --> Recebimento #################
    
    int Message::receiveCD(unsigned char* intendedDirectory){
      int errorTest;
      SubMessage resposta;
    
      errorTest = chdir((char*) intendedDirectory);
      if(errno = ENOENT){
        if(errno = EPERM){
          if (errorTest == -1){
            resposta.setData((unsigned char*)'0',0,0); // Manda um Nack
            send(soquete,resposta.objToString(),resposta.getSize()+4, 0);
          } else {
            resposta.setData((unsigned char*)'0',8,0); // Manda um OK
            send(soquete,resposta.objToString(),resposta.getSize()+4, 0);
          }
        } else { // Não há permissão para acessar o diretorio
          resposta.setData((unsigned char*)'1',14,0); // Manda um Erro
          send(soquete,resposta.objToString(),resposta.getSize()+4, 0);
        }
      } else { // Diretorio não existe
        resposta.setData((unsigned char*)'0',14,0); // Manda um Erro
        send(soquete,resposta.objToString(),resposta.getSize()+4, 0);
      }
    }
    
    //
    int Message::receiveData(unsigned char* fileName, int size){
      int numberOfMessages, messagesCounter = 0, seqCounter;
      int i, garbage, error, rv, success = 0, greaterSeq = 0;
      unsigned char *subData;
      char *receiptMessage = (char*)malloc(sizeof(char*)*64);
      struct pollfd ufds[1];
      SubMessage nack, ack, answer;
      ofstream fileOut;
      map<int,string> subMensagem;
      string finalMessage;
    
      ufds[0].fd = soquete;
      ufds[0].events = POLLIN;
    
      // Verifica quantas mensagens serao necessarias
      if (size%64){
        numberOfMessages = (size/64) + 1;
      }else{
        numberOfMessages = (size/64);
      }
      numberOfMessages++;  // +1 = Mensagem de FIM
    
    while(!success){
        rv = poll(ufds, 1, 500);
        if(rv){
          if(rv == -1){
            cout << "Erro no recebimento dos dados (messages.cpp::receiveData)" << endl;
            return -1;
          }else{
            recv(soquete, receiptMessage, 68*sizeof(char), 0);
            answer.stringToObj((unsigned char*)receiptMessage);
            // Lê começo da mensagem e vê se tem o delimitador de início
            if(answer.getStartMessage() == 0x7E){ // 0x7E = 01111110
              if(answer.checkParity()){
                if(messagesCounter == 0){ // Se a primeira mensagem tiver erro
                  nack.setData((unsigned char*)answer.getSeq(),0,0); // Manda um nack
                  send(soquete,nack.objToString(),nack.getSize()+4, 0);
                }else{
                  ack.setData((unsigned char*)((answer.getSeq()-1)%64),1,0);
                  send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                  messagesCounter = 0;
                }
              }else{
                if(answer.getType() == 13){
                  if(subMensagem[answer.getSeq()+(seqCounter*64)] == ""){
                    if(answer.getSeq() == 63){
                      seqCounter++;
                    }
                    subMensagem[answer.getSeq()+(seqCounter*64)] = (char*)answer.getData();
                    messagesCounter++;
                    if(answer.getSeq()+(seqCounter*64) > greaterSeq){
                      greaterSeq = answer.getSeq()+(seqCounter*64);
                    }
                    if(messagesCounter > 2){
                      ack.setData((unsigned char*)(greaterSeq%64),1,0);
                      send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                      messagesCounter = 0;
                    }
                  }else{
                    ack.setData((unsigned char*)answer.getSeq(),1,0);
                    send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                    messagesCounter = 0;
                  }
                }else if(answer.getType() == 15){
                  success = 1;
                  ack.setData((unsigned char*)((greaterSeq%64)+1),1,0);
                  send(soquete, ack.objToString(), ack.getSize()+4, 0); // Manda um ACK
                }
              }
            }
          }
        }else{
          cout << "Tempo limite de resposta excedido :c\n" << endl;
          cout << "TIMEOUT ATINGIDO (messages.cpp::receiveData)" << endl;
        }
      }
    
      for(i = 0; i < greaterSeq; ++i){
        finalMessage += subMensagem[i];
      }
      // Escrita no arquivo de saída.
      fileOut.open((char *)fileName, ios::out);
      fileOut << finalMessage;
      return 0;
    }