Как преодолеть проблему с прямым порядком байтов в проблеме TFTP клиента и сервера. - PullRequest
1 голос
/ 12 сентября 2011

Я создаю пакет WRQ для клиента TFTP в cPP.код отлично работает в системе Little Endian (ПК) и имеет проблемы с системой Big Endian при создании пакетов.

код

  #define TFTP_OPCODE_READ     1
  #define TFTP_OPCODE_WRITE    2
  #define TFTP_OPCODE_DATA     3
  #define TFTP_OPCODE_ACK      4
  #define TFTP_OPCODE_ERROR    5

  #define cTFTPPacket_MAX_SIZE 1024
  #define cTFTPPacket_DATA_SIZE 512

   #define TFTP_DEFAULT_TRANSFER_MODE "octet"           //"netascii", "octet", or "mail"

   typedef unsigned char BYTE;
   typedef unsigned short WORD;    

/////////////////////////      below is Packet.cpp file       ///////

bool cTFTPPacket::addByte(BYTE b) 
{
         if (mCurPacketSize >= cTFTPPacket_MAX_SIZE) 
          {
                return false;
          }
        mData[mCurPacketSize] = (unsigned char)b;
        mCurPacketSize++;
        return true;
}

 bool cTFTPPacket::addWord(WORD w) 
{
      if (!addByte(*(((BYTE*)&w)+1)))
    { 
    return false;
    }
    return (!addByte(*((BYTE*)&w)));
}

bool cTFTPPacket::addString(char* str) 
{
    int n = strlen(str);
    int i=0;
    for (i=0;i<n;i++) 
    {
      if (!addByte(*(str + i))) 
      {
          return false;
      }
    }
    return true;
}

Ожидаемый пакет

0x00 0x02 string 0x00 octet 0x00

Получить с прямым порядком байтов это

0x02 0x00 string 0x00 octet 0x00

Код для создания пакетов:

 bool cTFTPPacket::createWRQ(char* filename) 
 {
 /*      structure is the same as RRQ  */
   clear();
   addWord(TFTP_OPCODE_WRITE);
   addString(filename);
   addByte(0);
   addString(TFTP_DEFAULT_TRANSFER_MODE);
   addByte(0);
   return true;
 }

  bool cTFTPPacket::createACK(int packet_num)
 {
   clear();
   addWord(TFTP_OPCODE_ACK);
   addWord(packet_num);
   return true;
 }


   bool cTFTPPacket::createData(int block, char* mData, int data_size) 
   {
    /*         2 bytes    2 bytes       n bytes
    ----------------------------------------
     DATA  | 03    |   Block #  |    Data    |
    ---------------------------------------- */
   clear();                     // to clean the memory location
   addWord(TFTP_OPCODE_DATA);
   addWord(block);
   addMemory(mData, data_size);
   return true;
 }

 bool cTFTPPacket::addMemory(char* buffer, int len) 
 {
   bool oStatus=false;
   if (mCurPacketSize + len >= cTFTPPacket_MAX_SIZE)  
   {
      cout<<("Packet max size exceeded");
      oStatus= false;
   }
   else
   {
   memcpy(&(mData[mCurPacketSize]), buffer, len);
   mCurPacketSize += len;
   oStatus= true;
    }
    return oStatus;
  }


      BYTE cTFTPPacket::getByte(int offset) 
  {
       return (BYTE)mData[offset];
  }

 WORD cTFTPPacket::getWord(int offset) 
{
    WORD hi = getByte(offset);
    //WORD lo = getByte(offset + 1);
    WORD lo = getByte(offset + 1);
    return ((hi<<8)|lo);
}

WORD cTFTPPacket::getNumber() 
{
    if (this->isData() || this->isACK()) 
    {
        return this->getWord(2);
    } 
    else        
    {
        return 0;
    }
}

 bool cTFTPPacket::getString(int offset, char* buffer, int len)
 {
bool oStatus=false;
    if (offset > mCurPacketSize)
    {
        oStatus=false;
    }
    else if (len < mCurPacketSize - offset) 
    {
        oStatus= false;
    }
    else
    {
    memcpy(buffer, &(mData[offset]), mCurPacketSize - offset);
    oStatus= true;
    }
     return oStatus;
 }

 bool cTFTPPacket::createError(int error_code, char* message) {

 /*        2 bytes  2 bytes        string    1 byte
      ----------------------------------------
    ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
      ----------------------------------------  */
    clear();
    addWord(TFTP_OPCODE_ERROR);
    addWord(error_code);
    addString(message);
    addByte(0);
    return true;

 }

 int cTFTPPacket::getSize() 
 {
    return mCurPacketSize;
 }

  bool cTFTPPacket::setSize(int size) 
  {
    if (size <= cTFTPPacket_MAX_SIZE) 
    {
            mCurPacketSize = size;
            return true;
    }
    else 
    {
            return false;
    }
  }

 bool cTFTPPacket::isRRQ() 
 {
    return (this->getWord(0) == TFTP_OPCODE_READ);
 }

  bool cTFTPPacket::isWRQ() 
  {
     return (this->getWord(0) == TFTP_OPCODE_WRITE);
   }

   bool cTFTPPacket::isACK() 
   {
     return (this->getWord(0) == TFTP_OPCODE_ACK);
     }
    bool cTFTPPacket::isData() {
      return (this->getWord(0) == TFTP_OPCODE_DATA);
    }

    bool cTFTPPacket::isError() 
    {
    return (this->getWord(0) == TFTP_OPCODE_ERROR);
     }

    void cTFTPPacket::clear()      
    {
         mCurPacketSize = 0;
         memset(mData, mCurPacketSize, cTFTPPacket_MAX_SIZE);
     }

     unsigned char* cTFTPPacket::getData(int offset) 
    {
      return &(mData[offset]);
      }

    bool cTFTPPacket::copyData(int offset, char* dest, int length) 
    {
     bool oStatus=false;
         if (offset > this->getSize()) 
        {
        oStatus= false;
    }
    else if (length < (this->getSize() - offset)) 
    {
        oStatus= false; 
    }
    else
    {
        memcpy(dest, &(mData[offset]), (this->getSize()-offset));
        oStatus= true;
    }
    return oStatus;
 }

  void cTFTPPacket::dumpData() {
    xRM_DEBUG("\n--------------DATA DUMP---------------------\n");
    xRM_DEBUG("Size: " << mCurPacketSize );
    for (int i = 0; i < mCurPacketSize; i++) 
    {
            xRM_DEBUG(mData[i]);
            cout<<mData[i];
    }
   }

    cTFTPPacket::~cTFTPPacket() {

     }

Я понял, что проблема происходитв Addword и получить слово, как преодолеть эту проблему.и еще одна вещь, мой сервер с прямым порядком байтов (обычный компьютер с Linux) и аппаратное обеспечение с прямым порядком байтов

Ответы [ 3 ]

1 голос
/ 12 сентября 2011

Когда вы имеете дело с возможностью того, что одна из задействованных машин будет с прямым порядком байтов, вам нужно при отправке преобразовать все в сетевой порядок байтов.

Нужные вам функции: htonl, htons (хост в сеть длинный / короткий)

При получении данных вы конвертируете во все, что требуется локальному компьютеру, используя обратную;ntohl и ntohs.На машине с прямым порядком байтов они не работают, и данные остаются без изменений.На машине с прямым порядком байтов они преобразуются в правильный (байтовый порядок) порядок байтов.

Редактировать: В ответ на комментарий ОП ниже:

Ваш WORD являетсяunsigned short.Это означает, что вам нужно преобразовать его, используя htons() в вашей функции addWord():

bool cTFTPPacket::addWord(WORD w) 
{
    w = htons(w);
    if (!addByte(*(((BYTE*)&w)+1)))
    { 
        return false;
    }
    return (!addByte(*((BYTE*)&w)));
}

и затем повернуть процесс в вашей функции getWord():

WORD cTFTPPacket::getWord(int offset) 
{
    WORD hi = getByte(offset);
    //WORD lo = getByte(offset + 1);
    WORD lo = getByte(offset + 1);
    return nstoh((hi<<8)|lo);
}
0 голосов
/ 12 сентября 2011

«Традиционный» подход состоит в том, чтобы притворяться, что есть только два возможных порядка (хотя я видел по крайней мере три), и что все машины имеют два дополнения с 8-битными байтами.Лучшим подходом является логическая обработка числового формата.Для беззнаковых что-то вроде:

void
insertUnsigned16Bits( char* dest, unsigned value )
{
    *dest ++ = (value >> 8) & 0xFF;
    *dest ++ = (value     ) & 0xFF;
}

unsigned
extractUnsigned16Bits( char const* source )
{
    unsigned result = 0;
    result |= (*source ++ & 0xFF) << 8;
    result |= (*source ++ & 0xFF);
    return result;
}

Это легко распространяется на любой размер целых чисел без знака, которые могут быть представлены на вашем компьютере.

Для вывода со знаком, если формат определяет дополнение 2, простопреобразовать в без знака - стандарт требует, чтобы такие преобразования выполнялись правильно.На входе, чтобы быть действительно переносимым, вы должны прочитать в больший тип, проверить, больше ли прочитанное вами значение без знака, чем максимальное значение со знаком, и если это так, вычтите соответствующее значение без знака max;однако на большинстве машин будет работать только чтение без знака, а затем преобразование в подписанный тип.

0 голосов
/ 12 сентября 2011

Традиционный подход заключается в использовании htons (для преобразования 16-битного значения из хоста в порядок байтов сети) и ntohs (для преобразования из сети в порядок байтов хоста);аналогично ntohl и htonl для 32-битных значений.

...