mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
tlv: Add typesafe fromwire codegen for TLV namespaces
We were weaving in and out of generic code through `fromwire_tlvs` with custom parameters defining the types in that namespace. This hard-wires the parser with the namespace's types. Slowly trying to deprecate `fromwire_tlvs` in favor of this typesafe variant.
This commit is contained in:
committed by
Rusty Russell
parent
2255024ead
commit
5794c83b4d
@@ -66,6 +66,7 @@ struct ${tlv.struct_name()} {
|
|||||||
|
|
||||||
% for tlv in tlvs.values():
|
% for tlv in tlvs.values():
|
||||||
struct ${tlv.struct_name()} *${tlv.struct_name()}_new(const tal_t *ctx);
|
struct ${tlv.struct_name()} *${tlv.struct_name()}_new(const tal_t *ctx);
|
||||||
|
bool fromwire_${tlv.name}(const u8 **cursor, size_t *max, struct ${tlv.struct_name()} *record);
|
||||||
|
|
||||||
% if tlv.name in options.expose_tlv_type:
|
% if tlv.name in options.expose_tlv_type:
|
||||||
#define TLVS_${tlv.name.upper()}_ARRAY_SIZE ${len(tlv.messages)}
|
#define TLVS_${tlv.name.upper()}_ARRAY_SIZE ${len(tlv.messages)}
|
||||||
|
|||||||
@@ -3,10 +3,16 @@
|
|||||||
/* Original template can be found at tools/gen/impl_template */
|
/* Original template can be found at tools/gen/impl_template */
|
||||||
|
|
||||||
#include <${header_filename}>
|
#include <${header_filename}>
|
||||||
|
#include <assert.h>
|
||||||
#include <ccan/array_size/array_size.h>
|
#include <ccan/array_size/array_size.h>
|
||||||
#include <ccan/mem/mem.h>
|
#include <ccan/mem/mem.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef SUPERVERBOSE
|
||||||
|
#define SUPERVERBOSE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
% for comment in top_comments:
|
% for comment in top_comments:
|
||||||
/*${comment} */
|
/*${comment} */
|
||||||
% endfor
|
% endfor
|
||||||
@@ -211,6 +217,93 @@ ${static}const struct tlv_record_type tlvs_${tlv.name}[] = {
|
|||||||
{ ${msg.number}, towire_${msg.struct_name()}, fromwire_${msg.struct_name()} },
|
{ ${msg.number}, towire_${msg.struct_name()}, fromwire_${msg.struct_name()} },
|
||||||
% endfor
|
% endfor
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool fromwire_${tlv.name}(const u8 **cursor, size_t *max, struct ${tlv.struct_name()} *record)
|
||||||
|
{
|
||||||
|
size_t num_types = ${len(tlv.messages)};
|
||||||
|
const struct tlv_record_type *types = tlvs_${tlv.name};
|
||||||
|
while (*max > 0) {
|
||||||
|
struct tlv_field field;
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
*
|
||||||
|
* A `varint` is a variable-length, unsigned integer encoding
|
||||||
|
* using the [BigSize](#appendix-a-bigsize-test-vectors)
|
||||||
|
* format
|
||||||
|
*/
|
||||||
|
field.numtype = fromwire_bigsize(cursor, max);
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
* - if a `type` or `length` is not minimally encoded:
|
||||||
|
* - MUST fail to parse the `tlv_stream`.
|
||||||
|
*/
|
||||||
|
if (!*cursor) {
|
||||||
|
SUPERVERBOSE("type");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
field.length = fromwire_bigsize(cursor, max);
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
* - if a `type` or `length` is not minimally encoded:
|
||||||
|
* - MUST fail to parse the `tlv_stream`.
|
||||||
|
*/
|
||||||
|
if (!*cursor) {
|
||||||
|
SUPERVERBOSE("length");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
* - if `length` exceeds the number of bytes remaining in the
|
||||||
|
* message:
|
||||||
|
* - MUST fail to parse the `tlv_stream`.
|
||||||
|
*/
|
||||||
|
if (field.length > *max) {
|
||||||
|
SUPERVERBOSE("value");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
field.value = tal_dup_arr(record, u8, *cursor, field.length, 0);
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
* - if `type` is known:
|
||||||
|
* - MUST decode the next `length` bytes using the known
|
||||||
|
* encoding for `type`.
|
||||||
|
*/
|
||||||
|
field.meta = NULL;
|
||||||
|
for (size_t i = 0; i < num_types; i++)
|
||||||
|
if (types[i].type == field.numtype)
|
||||||
|
field.meta = &types[i];
|
||||||
|
|
||||||
|
if (field.meta) {
|
||||||
|
/* Length of message can't exceed 16 bits anyway. */
|
||||||
|
size_t tlvlen = field.length;
|
||||||
|
field.meta->fromwire(cursor, &tlvlen, record);
|
||||||
|
|
||||||
|
if (!*cursor)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* BOLT #1:
|
||||||
|
* - if `length` is not exactly equal to that required
|
||||||
|
* for the known encoding for `type`:
|
||||||
|
* - MUST fail to parse the `tlv_stream`.
|
||||||
|
*/
|
||||||
|
if (tlvlen != 0) {
|
||||||
|
SUPERVERBOSE("greater than encoding length");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We didn't read from *cursor through a fromwire, so
|
||||||
|
* update manually. */
|
||||||
|
*cursor += field.length;
|
||||||
|
}
|
||||||
|
/* We've read bytes in ->fromwire, so update max */
|
||||||
|
*max -= field.length;
|
||||||
|
tal_arr_expand(&record->fields, field);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
fail:
|
||||||
|
fromwire_fail(cursor, max);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
% endfor ## END TLV's
|
% endfor ## END TLV's
|
||||||
% for msg in messages: ## START Wire Messages
|
% for msg in messages: ## START Wire Messages
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user