1

For a school project, I have to develop a TFTP server in C. I have to build a packet in a array of char like this :

 2 bytes    2 bytes    n bytes
+--------+-----------+--------+
|  CODE  |  Block #  |  Data  |
+--------+-----------+--------+

Here is how I build this packet:

int tftp_make_data(char *buffer, size_t *length, uint16_t block, const char *data, size_t n) {
    memset(buffer, 0, *length);
    *length = 0;
    *(buffer) = DATA;
    *length += sizeof(uint16_t);
    *(buffer + *length) = block;
    *length += sizeof(uint16_t);
    memcpy(buffer + *length, data, n);
    *length += n;

    return 0;
}

This function fill buffer with the packet content and fill length with the size of the packet. This works fine if block is lower than 128. If it's greeter than 128, it becomes -128.

Can you help me?

Mathieu
  • 311
  • 2
  • 12
  • `*(buffer + *length) = block;` - you're assigning a `uint16_t` to a `char` (which is apparently `signed` on your platform, as most others). May want to rethink that. – WhozCraig Apr 09 '16 at 09:44
  • I used an array of uint8_t and it seems to work. Thank you :) – Mathieu Apr 09 '16 at 09:48

1 Answers1

3

Unless something is one byte in size, you cannot assign it to *buffer. Both of these assignments are incorrect:

*(buffer) = DATA;
*(buffer + *length) = block;

When you are writing uint16_t, use memcpy:

uint16_t dataToWrite = ...;
memcpy(buffer + *length, &dataToWrite, sizeof(uint16_t));

You are not done yet, because you need to decide what to assign dataToWrite. If you do this

uint16_t dataToWrite = block;

the data sent over the wire will be in hardware-specific order, which should never happen. Instead, you need to use one of hton-family functions to convert your number to network format:

uint16_t dataToWrite = htons(block);

I check it on the same machine, just with

printf("block : %d\n", packet[sizeof(uint_16)]);

This is incorrect, for the same reason as the assignment: packet[sizeof(uint_16)] makes an int or unsigned int from the char/uint8_t value stored at position sizeof(uint_16), and it also ignores the other byte.

To fix this you need to use memcpy again. Of course, if you used htons on the writing side, you need to use ntohs before printing:

uint16_t dataToPrint;
memcpy(dataToPrint, &packet[sizeof(uint16_t)], sizeof(uint16_t));
dataToPrint = ntohs(dataToPrint);
printf("block : %u\n", dataToPrint);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523