ctftp

How to create a custom char in c?


I have to create a request datagram (RRQ) for a Tftp client like this:

enter image description here

But i can't use a struct because the fields have variable length.

i tried the struct and something iterating on a char.


Solution

  • Create an array of bytes and append to it. You can make this easier by using pointer arithmetic to keep track of where you've written, kind of like a cursor.

    We can make life easier for ourselves by tracking where in the request memory the archive and mode strings start so we can easily find them later.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    typedef struct {
        char *archive;
        char *mode;
        char *request;
    } Read_Request;
    
    Read_Request *read_request_create(const char *archive, const char *mode) {
        Read_Request *rrq = malloc(sizeof(Read_Request));
    
        // Allocate sufficient memory for the opcode and both strings,
        // including the terminating nulls.
        rrq->request = malloc(2 + strlen(archive) + 1 + strlen(mode) + 1);
    
        // Start the request with the opcode.
        // 2 byte network byte order integer.
        uint16_t opcode = htons(1);
        memcpy(rrq->request, &opcode, sizeof(opcode));
    
        // Put the start of the archive 2 bytes in, just after the opcode.
        rrq->archive = rrq->request + 2;
    
        // Copy the archive string into position.
        strcpy(rrq->archive, archive);
    
        // Put the start of the mode just after the archive and its null byte.
        rrq->mode = rrq->archive + strlen(archive) + 1;
    
        // Append the mode.
        strcpy(rrq->mode, mode);
    
        return rrq;
    }
    

    Then printing is easy. Print the 2 byte opcode. Then since a C string stops at a null byte, we can simply print the archive and mode strings.

    void read_request_print(Read_Request *rrq) {
        // Turn the first two bytes (the opcode) into two hex characters.
        unsigned char *opcode = (unsigned char *)rrq->request;
        printf("opcode: %0x%0x\n", opcode[0], opcode[1]);
    
        printf("archive: '%s'\n", rrq->archive);
    
        printf("mode: '%s'\n", rrq->mode);
    }
    
    int main() {
        Read_Request *rrq = read_request_create("archive", "mode");
    
        read_request_print(rrq);
    }