如何解决TFTP客户端和服务器通信中小端到大端的问题?

发布于 2024-12-03 21:23:56 字数 5620 浏览 2 评论 0原文

我正在 cPP 中为 TFTP 客户端创建 WRQ 数据包。该代码在 Little Endian 系统(PC)中工作正常,但在创建数据包时在 Bi​​g 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 和 get Word 如何解决这个问题。 还有一件事,我的服务器是小端(普通的 Linux 机器),而硬件是大端

i am creating WRQ packet for TFTP client in cPP. the code works fine in Little endian system (PC) and have proble m with Big Endian system while creating packets.

the code is

  #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;
}

Expected packet is

0x00 0x02 string 0x00 octet 0x00

Obtain in big endian is

0x02 0x00 string 0x00 octet 0x00

Code to create the Packets are

 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() {

     }

i figured the proble is occuring in Addword and get Word how to over come this problem.
and one more thing my server is little endian (normal linux machine) and hardware is big endian

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

手长情犹 2024-12-10 21:23:56

当您处理其中一台机器可能是大端字节序时,您需要在发送时将所有内容转换为网络字节顺序。

您需要的函数是 htonl、htons(主机到网络长/短)

当接收到数据时,您可以使用相反的方法将数据转换为本地计算机需要的任何内容; ntohlntohs。在大端机器上,这些是无操作的并且数据保持不变。在小端机器上,它们转换为正确的(小端)字节顺序。

编辑:回复下面OP的评论:

您的WORD是一个无符号短。这意味着您需要在 addWord() 函数中使用 htons() 对其进行转换:

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);
}

When you're dealing with the possibility of one of the machines involved being big endian you need to convert everything to network byte order when you send.

The functions you need are htonl, htons (host to network long / short)

When receiving the data you convert to whatever the local machine needs using the reverse; ntohl and ntohs. On the big endian machine these are no-op and the data remains unchanged. On the little endian machine they convert to the correct (little endian) byte order.

Edit: In reply to OP's comment below:

Your WORD is an unsigned short. This means you need to convert it using htons() in your addWord() function:

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

And then reverse the process in your getWord() function:

WORD cTFTPPacket::getWord(int offset) 
{
    WORD hi = getByte(offset);
    //WORD lo = getByte(offset + 1);
    WORD lo = getByte(offset + 1);
    return nstoh((hi<<8)|lo);
}
写给空气的情书 2024-12-10 21:23:56

“传统”方法是假装只有两个
可能的顺序(虽然我至少见过三个),并且所有
机器是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的补码,只需转换
到无符号——标准要求这样的转换才能正确进行
事物。在输入方面,要真正便携,您必须读取更大的内容
type,测试读取的无符号值是否大于
最大有符号值,如果是,则减去相应的无符号值
最大限度;然而,在大多数机器上,只需读入无符号,然后
转换为有符号类型将会起作用。

The "traditional" approach is to pretend that there are only two
possible orderings (although I've seen at least three), and that all
machines are twos complement with 8 bit bytes. A better approach is to
process the numeric format logically. For unsigned, something like:

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;
}

This easily extends to any size of unsigned integers that can be
represented on your machine.

For signed output, if the format specifies 2's complement, just convert
to unsigned—the standard requires such conversions to do the right
thing. On input, to be really portable, you have to read into a larger
type, test whether the unsigned value you read is greater than the
maximum signed value, and if so, subtract the corresponding unsigned
max; on most machines, however, just reading into an unsigned, then
converting to the signed type will work.

我不在是我 2024-12-10 21:23:56

传统的方法是使用 htons(将 16 位值从主机字节顺序转换为网络字节顺序)和 ntohs(从网络字节顺序转换为主机字节顺序);类似地,对于 32 位值,ntohlhtonl

The traditional approach is to use htons (to convert a 16 bit value from host to network byte order) and ntohs (to convert from network to host byte order); similarly ntohl and htonl for 32bit values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文