Search code examples
ctftp

uint16_t in array of char


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?


Solution

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