1

I'm writing TFTP client in C. So far I had no problem with reading file into buffers(512 B) and transfer it to the server. However I'm struggling to read files like PDF that contains binary data.

        size_t nmemb = fread(data_buf, sizeof(char), 512, fp);
        ...
        /* Create DATA packet and send it to TFTP server */ 
        count = sprintf(message, "%c%c%c%c%s", 0, DATA, 0, block_number, data_buf); 
        sendto(sock, message, count, 0, (const struct sockaddr *)&server, sizeof(server));

I tested this with printing every buffer separately: printf("%d: %s\n", nmemb, data_buf); Looks like nmemb is always 512, which is correct, but printf() stops printing data when it gets to a first NULL byte, which I'm sure represents the end of a given string(buffer).

Buffer data within DATA packet that is sent through a TFTP protocol are also cut off at first occurrence of NULL byte - I tested this in Wireshark.

Is there a way to fix this problem by using some alternative to fread() or changing a way packet is sent through socket? Thanks for any answer.

ahOw22
  • 25
  • 5
  • You seem to already know that there is a difference between text and binary. Don't use string functions like `snprintf` on binary data. It just won't work as you have found. Use direct memory copy/set operations. – kaylum Nov 11 '21 at 20:34
  • The data in a `.pdf` file _can_ contain binary [non-printable] chars. And, one of those can be 0x00. So, you can _not_ use `printf` to print that data. And, likewise, you can't use `sprintf` for the reason you already stated. It stops at the EOS (0x00) char. The issue with `sprintf` is why it stops short in transmission and wireshark can't see it. – Craig Estey Nov 11 '21 at 20:34

1 Answers1

2

You can't use the printf family of functions for this since they stop when \0 is encountered.

First approach: Use memcpy:

size_t nmemb = fread(data_buf, 1, sizeof data_buf, fp);

char message[sizeof data_buf + 4]; // presumably

count = sprintf(message, "%c%c%c%c", 0, DATA, 0, block_number);
memcpy(message + count, data_buf, nmemb);

Second approach (the preferred way): Avoid the copying and fread directly into the buffer you'll later send:

char message[512 + 4] = {0, DATA, 0, block_number};
size_t nmemb = fread(message + 4, 1, 512, fp);
sendto(sock, message, nmemb + 4, 0, (const struct sockaddr *)&server, sizeof(server))

Note: sizeof(char) is always 1. It can't be anything else.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108