0

I want to send a datagram UDP message via sendto with 4-byte address, 1 short int number, and 4 bytes int distance. So it should be exactly 9-bytes. How can i do it? I already have tried to convert those values and put them in buffer, but it didn't work.

sendto(sockfd, &message, sizeof(message), 0, (struct sockaddr*) &server_address, sizeof(server_address));

EDIT: i also tried to create, but it has 12 bytes.

 struct msg {
      uint32_t dist;
      uint8_t num ;
       struct in_addr addr;
  
};
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • 1
    `message` is likely being [padded](https://en.wikipedia.org/wiki/Data_structure_alignment). We need to see the definition to be sure, though. – user4581301 Apr 14 '21 at 19:14
  • @user4581301 edited. Yes, its being padded, the question is how can i create structure that will have exactly 9 bytes. I know that i can get 4 byte ip address using for example inet_aton("127.0.0.1", &message.addr), but i dont know how to put in in buffer and keep the size of 4 bytes. – jankrisjan Apr 14 '21 at 19:20
  • Use compiler directives to turn off the padding, such as `#pragma pack(push, 1)`, `__attribute__((packed))`, etc, depending on what your compiler supports – Remy Lebeau Apr 14 '21 at 19:26
  • 1
    Unrelated: Because I'm a paranoid bastard, I'd replace `in_addr` with another `uint32_t`. The implementation is usually an unsigned 32 bit integer, but you may get some interesting surprises. – user4581301 Apr 14 '21 at 19:57

1 Answers1

1

The most portable way is to assemble the bytes into a buffer yourself:

uint8_t buf[64];  // make sure this is large enough to hold the bytes
uint8_t * b = buf;

uint32_t neDist = htonl(msg.dist);   // send multi-byte values in big-endian form
memcpy(b, &neDist, sizeof(neDist));
b += sizeof(neDist);

memcpy(b, &msg.num, sizeof(msg.num));
b += sizeof(msg.num);

uint32_t neAddr = htonl(msg.addr.s_addr);
memcpy(b, &neAddr, sizeof(neAddr));
b += sizeof(neAddr);

uint32_t numBytesToSend = (b-buf);
sendto(sockfd, buf, numBytesToSend, 0, (struct sockaddr*) &server_address, sizeof(server_address));

... and then on the receiving side, something like:

uint8_t buf[64];  // make sure this is large enough to hold the bytes
int32_t numBytesReceived = recvfrom(sockfd, buf, sizeof(buf), ...);
if (numBytesReceived > 0)
{
    struct msg m;

    uint8_t * b = buf;
    uint8_t * fib = buf+numBytesReceived;  // pointer to the first invalid byte

    if ((fib-b) >= sizeof(m.dist))
    {
       uint32_t neDist;
       memcpy(&neDist, b, sizeof(neDist));
       b += sizeof(neDist);
       m.dist = ntohl(neDist);  // convert from big-endian back to local-endian

       if ((fib-b) >= sizeof(m.num))
       {
          memcpy(&m.num, b, sizeof(m.num));
          b += sizeof(m.num);

          if ((fib-b) >= sizeof(m.addr.s_addr))
          {
             uint32 neAddr;
             memcpy(&neAddr, b, sizeof(neAddr));
             m.addr.s_addr = ntohl(neAddr);

             printf("At this point, (m) is fully populated and ready for use\n");
          }
       }
    }
}
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234