Skip to content

TFTP Assembling the Parser

Elbasiouny, Mahmoud edited this page Feb 27, 2026 · 6 revisions

We've built parsers for every TFTP packet type: RRQ/WRQ, DATA, ACK, and ERROR. Now we wire them together into a single top-level parser using h_choice.

Source files: tftp.c, main.c
Hammer concepts: h_choice · h_parse


Choosing Between Packet Types with h_choice

Each TFTP packet starts with a 2-byte opcode that determines its type. Since each sub-parser already validates its own opcode, we can use h_choice to try each parser in order:

HParser *parser = h_choice(
    rrqwrqParser(),
    dataParser(),
    ackParser(),
    errpktParser(),
    NULL
);

h_choice(p1, p2, ..., NULL)

Tries each parser in order from left to right. Returns the result of the first parser that succeeds. If none succeed, the entire parse fails.

Because each sub-parser begins by checking for its specific opcode, a RRQ packet (opcode 1) will fail the dataParser() check (opcode 3) immediately, and h_choice will move on to the next option. This makes the ordering of parsers in h_choice flexible - any order works.


Running the Parser with h_parse

In main.c, the parser is called against an input buffer:

HParseResult *result = h_parse(parser, input, inputLength);

h_parse takes the top-level parser, a byte array, and its length. It returns a non-NULL HParseResult on success, or NULL on failure.

If the result is non-NULL, the input matched one of the four TFTP packet types. If NULL, the packet was structurally invalid.


Summary

Combinator Purpose in This Parser
h_choice(a, b, ..., NULL) Try each packet type until one matches
h_parse(parser, input, len) Run the assembled parser against raw bytes

The key insight is that each sub-parser is self-contained - it validates its own opcode, fields, and structure. The top-level h_choice simply dispatches to the right one.


Next: Running and Testing

Previous: ERROR Packets

Clone this wiki locally