3

I'm making my own client-server application in C that implements the TFTP protocol. After reading the TFTP's RFC and making working a simple socket client-server app, now I'm a little confused on how to create the specific packets that have to be created for the TFTP protocol.

For example, the WRQ packet has to be this way:

        2 bytes     string    1 byte     string   1 byte
        ------------------------------------------------
       | Opcode |  Filename  |   0  |    Mode    |   0  |
        ------------------------------------------------

which is extracted from the official RFC.

I have a .h in which I define all the structures for the packets, but I'm not sure if I'm doing correctly and I'm not being lucky finding information on the web.

The struct I created for this packet is:

    struct WRQ {
      signed short int opcode; //2 bytes
      char * filename; // N bytes
    char zero_0; // 1 byte
      char * mode; // N Bytes
    char zero_1; // 1 byte
    };

I have two doubts:

a) when I make a sizeof(struct WRQ) it returns 20 bytes. Which is not the size I want to get. Why does this happens?

b) How do I have to define the strings? because I want the server to recieve the string itself, and, I think, this way, It will recieve the pointer to the string in the client machine.

I hope that all is clear and you could help me because I'm stuck at the moment!

4
  • you might get answer for your a question stackoverflow.com/questions/5596428/… Commented Apr 10, 2011 at 15:21
  • Question: how are the string lengths in the packet handled? Are they null terminated, have a byte length field, or even fixed length? Commented Apr 10, 2011 at 15:28
  • Thank you Peacelyk for the answer! Commented Apr 10, 2011 at 15:32
  • Duck, the strings al null terminated Commented Apr 10, 2011 at 15:32

4 Answers 4

2

The following code (with no error checking) is one possible way of building up the packet and sending it. Note that it assumes that both filename and mode are not NULL. I don't know if that is a valid assumption or not. Even if it is, it would be wise to have a check for NULL before using them in real code:

struct WRQ *p;
int packetLen;
char *buf;
char *pos;
int ret;

// compute packet length.  Start with fixed size data
packetLen = sizeof( p->opcode ) + sizeof( p->zero_0 ) + sizeof( p->zero_1 );
// This assumes (possibly incorrectly) that filename and mode are not null
packetLen += strlen( p->filename ) + 1;
packetLen += strlen( p->mode ) + 1;

// allocate the buffer
buf = malloc( packetLen ); 
pos = buf;

// and start filling it in
// I am assuming (but didn't study the RFC that it should be network byte order)
*(signed short int*)pos = htons( p->opcode );
pos += sizeof( p->opcode );
strcpy( pos, p->filename );
pos += strlen( p->filename ) + 1;
*pos = p->zero_0;
strcpy( pos, p->mode );
pos += strlen( p->mode ) + 1;
*pos = p->zero_1;

ret = send( s, buf, packetLen, flags );

free( buf );
Sign up to request clarification or add additional context in comments.

Comments

1

In your code, char * filename; is a pointer to a char. This means that filename only occupies 4 bytes. Even if your string is 1000 bytes long, since filename is simply a pointer, it just contains the 4-byte memory address of the first character of your string.

So you have two solutions: use char filename[MAX_LENGTH] to declare a string of size MAX_LENGTH and always pass that. Or, you can include another field, say, "filename_length", which tells you how many bytes to expect when you read the filename field.

(The above is actually false. filename may not be 4 bytes long. filename will be sizeof(char*) bytes long. This is probably 4 bytes on your computer. But pointers are not always 4 bytes, and nowadays people are getting into a lot of trouble for assuming a 4-byte pointer on 64-bit architectures. So I'm just sayin'. Don't downvote me.)

To answer your second question - why is sizeof() 20 bytes? The compiler will pad pieces of the struct with extra bytes so that each member fits inside a 4-byte boundary. The compiler can work efficiently with "words" rather than weird-sized structures. (Again, the "4" just depends on the architecture. Each architecture has its own "word" length.) This known as alignment. There is an excellent SO thread which gives more detail: Why isn't sizeof for a struct equal to the sum of sizeof of each member?

Comments

1

You can't just put a char* in there and expect it to work, because that's a pointer and you need the actual character data to appear in the packet (a pointer passed between two programs will almost never work!). Since the filename portion of the packet is variable-length, you can't represent the whole packet as a struct as you are trying to do. Instead, you probably should dynamically generate the packet by concatenating the pieces on demand, such as with a function having this signature:

vector<char> makePacket(uint16_t opcode, const char* filename, const char* mode);

2 Comments

I thought that it cannot be expressed that way, so... How can I do this? I've never used the vector<char> type in C... I don't know how to use it to determine the fields of the packet... Thanks!
Sorry, I said vector<char> but that's a C++ thing! If you're using straight C then the function would need to return a C string (either have it allocate and return a char* which the caller has to free, or pass in a char* buffer and size--I'd do the latter).
0

C structures can't have a variable size. You'll have to define "filename" and "mode" as char field_name [preset size]; or construct the structure by hand in a memory buffer at run time.

Finally, if what you need is a TFTP implementation in C, you can bet someone has written if already. E.g. there's an BSD'ed tftp-hpa used in a variety of Linux distributions.

1 Comment

I'll try to make it doing it in a char * buff variable, thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.