mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
e12b5c3824
This is the counterpart to the typesafe deserialization function implemented in an earlier commit.
499 lines
14 KiB
Plaintext
499 lines
14 KiB
Plaintext
/* This file was generated by generate-wire.py */
|
|
/* Do not modify this file! Modify the _csv file it was generated from. */
|
|
/* Original template can be found at tools/gen/impl_template */
|
|
|
|
#include <${header_filename}>
|
|
#include <assert.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <ccan/mem/mem.h>
|
|
#include <ccan/tal/str/str.h>
|
|
#include <stdio.h>
|
|
|
|
#ifndef SUPERVERBOSE
|
|
#define SUPERVERBOSE(...)
|
|
#endif
|
|
|
|
% for comment in top_comments:
|
|
/*${comment} */
|
|
% endfor
|
|
% for enum_set in enum_sets:
|
|
|
|
const char *${enum_set['name']}_name(int e)
|
|
{
|
|
static char invalidbuf[sizeof("INVALID ") + STR_MAX_CHARS(e)];
|
|
|
|
switch ((enum ${enum_set['name']})e) {
|
|
% for msg in enum_set['set']:
|
|
case ${msg.enum_name()}: return "${msg.enum_name()}";
|
|
% endfor
|
|
}
|
|
|
|
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
|
|
return invalidbuf;
|
|
}
|
|
% endfor
|
|
## START PARTIALS
|
|
## Subtype and TLV-msg towire_
|
|
<%def name="towire_subtype_field(fieldname, f, ptr)">\
|
|
% if f.is_array() or f.is_varlen():
|
|
% if f.type_obj.has_array_helper():
|
|
towire_${f.type_obj.name}_array(${ptr}, ${fieldname}, ${f.size('tal_count(' + fieldname + ')')});
|
|
% else:
|
|
for (size_t i = 0; i < ${f.size('tal_count(' + fieldname + ')')}; i++)
|
|
% if f.type_obj.is_assignable() or f.type_obj.has_len_fields():
|
|
towire_${f.type_obj.name}(${ptr}, ${fieldname}[i]);
|
|
% else:
|
|
towire_${f.type_obj.name}(${ptr}, ${fieldname} + i);
|
|
% endif
|
|
% endif
|
|
% elif f.len_field_of:
|
|
towire_${f.type_obj.name}(${ptr}, ${f.name});
|
|
% else:
|
|
towire_${f.type_obj.name}(${ptr}, ${'' if f.type_obj.is_assignable() else '&'}${fieldname});
|
|
% endif
|
|
</%def>
|
|
## Subtype and TLV-msg fromwire
|
|
<%def name="fromwire_subtype_field(fieldname, f, ctx)">\
|
|
<%
|
|
type_ = f.type_obj.name
|
|
typename = f.type_obj.type_name()
|
|
if f.type_obj.is_varsize():
|
|
typename += ' *'
|
|
%>\
|
|
% if f.is_varlen():
|
|
${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, ${f.size('*plen')}) : NULL;
|
|
% endif
|
|
% if f.is_array() or f.is_varlen():
|
|
% if f.type_obj.has_array_helper():
|
|
fromwire_${type_}_array(cursor, plen, ${fieldname}, ${f.size('*plen')});
|
|
% else:
|
|
% if f.is_implicit_len():
|
|
for (size_t i = 0; *plen != 0; i++)
|
|
% else:
|
|
for (size_t i = 0; i < ${f.size()}; i++)
|
|
% endif
|
|
% if f.type_obj.is_assignable():
|
|
(${fieldname})[i] = fromwire_${type_}(cursor, plen);
|
|
% elif f.is_varlen() and f.type_obj.is_varsize():
|
|
(${fieldname})[i] = fromwire_${type_}(${ctx}, cursor, plen);
|
|
% else:
|
|
fromwire_${type_}(cursor, plen, ${fieldname} + i);
|
|
% endif
|
|
% endif
|
|
% else:
|
|
% if f.type_obj.is_assignable():
|
|
${ f.name if f.len_field_of else fieldname} = fromwire_${type_}(cursor, plen);
|
|
% elif f.type_obj.is_varsize():
|
|
${fieldname} = *fromwire_${type_}(${ctx}, cursor, plen);
|
|
% else:
|
|
fromwire_${type_}(cursor, plen, &${fieldname});
|
|
% endif
|
|
%endif
|
|
</%def>
|
|
## END PARTIALS
|
|
## FIXME: extract out partials for the method declarations
|
|
## (shared between here and header_template)
|
|
% for subtype in subtypes: ## START Subtypes
|
|
|
|
/* SUBTYPE: ${subtype.name.upper()} */
|
|
% for c in subtype.type_comments:
|
|
/*${c} */
|
|
% endfor
|
|
<%
|
|
static = '' if options.expose_subtypes else 'static '
|
|
%>\
|
|
${static}void towire_${subtype.name}(u8 **p, const ${subtype.type_name()} *${subtype.name})
|
|
{
|
|
% for f in subtype.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name} = tal_count(${subtype.name}->${f.len_field_of});
|
|
% endfor
|
|
|
|
% for f in subtype.fields.values():
|
|
% for c in f.field_comments:
|
|
/*${c} */
|
|
% endfor
|
|
<%
|
|
fieldname = '{}->{}'.format(subtype.name,f.name)
|
|
%>\
|
|
${towire_subtype_field(fieldname, f, 'p')}\
|
|
% endfor
|
|
}
|
|
% if subtype.is_varsize():
|
|
${static}${subtype.type_name()} *
|
|
fromwire_${subtype.name}(const tal_t *ctx, const u8 **cursor, size_t *plen)
|
|
% else:
|
|
${static}void fromwire_${subtype.name}(${'const tal_t *ctx, ' if subtype.needs_context() else ''}const u8 **cursor, size_t *plen, ${subtype.type_name()} *${subtype.name})
|
|
% endif
|
|
{
|
|
% if subtype.is_varsize():
|
|
${subtype.type_name()} *${subtype.name} = tal(ctx, ${subtype.type_name()});
|
|
% endif
|
|
## Length field declarations
|
|
% for f in subtype.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name};
|
|
% endfor
|
|
|
|
% for f in subtype.fields.values():
|
|
% for c in f.field_comments:
|
|
/*${c} */
|
|
% endfor
|
|
<%
|
|
fieldname = '{}->{}'.format(subtype.name,f.name)
|
|
ctx = subtype.name
|
|
%> \
|
|
${fromwire_subtype_field(fieldname, f, ctx)}\
|
|
% endfor
|
|
% if subtype.is_varsize():
|
|
|
|
return ${subtype.name};
|
|
% endif
|
|
}
|
|
% endfor ## END Subtypes
|
|
<%def name="fromwire_phrase(f, type_, varsized)" >\
|
|
%if f.type_obj.is_assignable():
|
|
*${f.name} = fromwire_${type_}(&cursor, &plen);
|
|
% elif varsized:
|
|
*${f.name} = fromwire_${type_}(ctx, &cursor, &plen);
|
|
% else:
|
|
fromwire_${type_}(${'ctx, ' if f.needs_context() else ''}&cursor, &plen, ${'*' if f.is_optional else ''}${f.name});
|
|
% endif
|
|
</%def>
|
|
% for tlv in tlvs.values(): ## START TLV's
|
|
|
|
${tlv.type_name()} *${tlv.struct_name()}_new(const tal_t *ctx)
|
|
{
|
|
/* Initialize everything to NULL. (Quiet, C pedants!) */
|
|
${tlv.type_name()} *inst = talz(ctx, struct ${tlv.struct_name()});
|
|
|
|
/* Initialized the fields to an empty array. */
|
|
inst->fields = tal_arr(inst, struct tlv_field, 0);
|
|
return inst;
|
|
}
|
|
|
|
% for msg in tlv.messages.values():
|
|
/* ${tlv.name.upper()} MSG: ${msg.name} */
|
|
static u8 *towire_${msg.struct_name()}(const tal_t *ctx, const void *vrecord)
|
|
{
|
|
const struct ${tlv.struct_name()} *r = vrecord;
|
|
u8 *ptr;
|
|
|
|
if (!r->${msg.name})
|
|
return NULL;
|
|
|
|
% for f in msg.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name} = tal_count(r->${msg.name}->${f.len_field_of});
|
|
% endfor
|
|
|
|
ptr = tal_arr(ctx, u8, 0);
|
|
% for f in msg.fields.values():
|
|
<% fieldname = 'r->{}->{}'.format(msg.name, f.name) %>\
|
|
${towire_subtype_field(fieldname, f, '&ptr')}\
|
|
% endfor
|
|
return ptr;
|
|
}
|
|
static void fromwire_${msg.struct_name()}(const u8 **cursor, size_t *plen, void *vrecord)
|
|
{
|
|
struct ${tlv.struct_name()} *r = vrecord;
|
|
## Length field declarations
|
|
% for f in msg.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name};
|
|
% endfor
|
|
|
|
r->${msg.name} = tal(r, struct ${msg.struct_name()});
|
|
% for f in msg.fields.values():
|
|
<%
|
|
fieldname = 'r->{}->{}'.format(msg.name, f.name)
|
|
ctx = 'r->{}'.format(msg.name)
|
|
%>\
|
|
${fromwire_subtype_field(fieldname, f, ctx)}\
|
|
% endfor
|
|
}
|
|
% endfor
|
|
|
|
<% static = '' if tlv.name in options.expose_tlv_type else 'static '
|
|
%>\
|
|
${static}const struct tlv_record_type tlvs_${tlv.name}[] = {
|
|
% for msg in tlv.ordered_msgs():
|
|
{ ${msg.number}, towire_${msg.struct_name()}, fromwire_${msg.struct_name()} },
|
|
% endfor
|
|
};
|
|
|
|
void towire_${tlv.name}(u8 **pptr,
|
|
const void *record)
|
|
{
|
|
size_t num_types = ${len(tlv.messages)};
|
|
const struct tlv_record_type *types = tlvs_${tlv.name};
|
|
if (!record)
|
|
return;
|
|
|
|
for (size_t i = 0; i < num_types; i++) {
|
|
u8 *val;
|
|
if (i != 0)
|
|
assert(types[i].type > types[i-1].type);
|
|
val = types[i].towire(NULL, record);
|
|
if (!val)
|
|
continue;
|
|
|
|
/* BOLT #1:
|
|
*
|
|
* The sending node:
|
|
...
|
|
* - MUST minimally encode `type` and `length`.
|
|
*/
|
|
towire_bigsize(pptr, types[i].type);
|
|
towire_bigsize(pptr, tal_bytelen(val));
|
|
towire(pptr, val, tal_bytelen(val));
|
|
tal_free(val);
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
bool ${tlv.name}_is_valid(const struct ${tlv.struct_name()} *record, size_t *err_index)
|
|
{
|
|
size_t numfields = tal_count(record->fields);
|
|
bool first = true;
|
|
u64 prev_type = 0;
|
|
for (int i=0; i<numfields; i++) {
|
|
struct tlv_field *f = &record->fields[i];
|
|
if (f->numtype % 2 == 0 && f->meta == NULL) {
|
|
/* BOLT #1:
|
|
* - otherwise, if `type` is unknown:
|
|
* - if `type` is even:
|
|
* - MUST fail to parse the `tlv_stream`.
|
|
* - otherwise, if `type` is odd:
|
|
* - MUST discard the next `length` bytes.
|
|
*/
|
|
SUPERVERBOSE("unknown even");
|
|
if (err_index != NULL)
|
|
*err_index = i;
|
|
return false;
|
|
} else if (!first && f->numtype <= prev_type) {
|
|
/* BOLT #1:
|
|
* - if decoded `type`s are not monotonically-increasing:
|
|
* - MUST fail to parse the `tlv_stream`.
|
|
*/
|
|
if (f->numtype == prev_type)
|
|
SUPERVERBOSE("duplicate tlv type");
|
|
else
|
|
SUPERVERBOSE("invalid ordering");
|
|
if (err_index != NULL)
|
|
*err_index = i;
|
|
return false;
|
|
}
|
|
first = false;
|
|
prev_type = f->numtype;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
% endfor ## END TLV's
|
|
% for msg in messages: ## START Wire Messages
|
|
|
|
% if msg.if_token:
|
|
#if ${msg.if_token}
|
|
% endif
|
|
/* WIRE: ${msg.name.upper()} */
|
|
% for c in msg.msg_comments:
|
|
/*${c} */
|
|
% endfor
|
|
u8 *towire_${msg.name}(const tal_t *ctx${''.join([f.arg_desc_to() for f in msg.fields.values()])})
|
|
{
|
|
## FIXME: we're ignoring TLV's rn
|
|
% for f in msg.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name} = tal_count(${f.len_field_of});
|
|
% endfor
|
|
u8 *p = tal_arr(ctx, u8, 0);
|
|
|
|
towire_u16(&p, ${msg.enum_name()});
|
|
% for f in msg.fields.values():
|
|
% for c in f.field_comments:
|
|
/*${c} */
|
|
% endfor
|
|
% if f.is_array() or f.is_varlen():
|
|
% if f.type_obj.has_array_helper():
|
|
towire_${f.type_obj.name}_array(&p, ${f.name}, ${f.size('tal_count(' + f.name + ')')});
|
|
% else:
|
|
for (size_t i = 0; i < ${f.size('tal_count(' + f.name + ')')}; i++)
|
|
% if f.type_obj.is_assignable() or f.type_obj.is_varsize():
|
|
towire_${f.type_obj.name}(&p, ${f.name}[i]);
|
|
% else:
|
|
towire_${f.type_obj.name}(&p, ${f.name} + i);
|
|
% endif
|
|
% endif
|
|
% elif f.type_obj.is_tlv():
|
|
towire_tlvs(&p, tlvs_${f.type_obj.tlv.name}, ARRAY_SIZE(tlvs_${f.type_obj.tlv.name}), ${f.name});
|
|
% elif f.is_optional: ## is optional?
|
|
if (!${f.name})
|
|
towire_bool(&p, false);
|
|
else {
|
|
towire_bool(&p, true);
|
|
towire_${f.type_obj.name}(&p, ${'*' if f.type_obj.is_assignable() else ''}${f.name});
|
|
}
|
|
% else: ## all other cases
|
|
towire_${f.type_obj.name}(&p, ${f.name});
|
|
% endif
|
|
% endfor
|
|
|
|
return memcheck(p, tal_count(p));
|
|
}
|
|
bool fromwire_${msg.name}(${'const tal_t *ctx, ' if msg.needs_context() else ''}const void *p${''.join([f.arg_desc_from() for f in msg.fields.values()])})
|
|
{
|
|
% if msg.get_len_fields():
|
|
% for f in msg.get_len_fields():
|
|
${f.type_obj.type_name()} ${f.name};
|
|
% endfor
|
|
|
|
% endif
|
|
const u8 *cursor = p;
|
|
size_t plen = tal_count(p);
|
|
|
|
if (fromwire_u16(&cursor, &plen) != ${msg.enum_name()})
|
|
return false;
|
|
% for f in msg.fields.values():
|
|
<%
|
|
typename = f.type_obj.type_name()
|
|
if f.type_obj.is_varsize():
|
|
typename = typename + ' *'
|
|
type_ = f.type_obj.name
|
|
varsized = f.type_obj.is_varsize()
|
|
%> \
|
|
% for c in f.field_comments:
|
|
/*${c} */
|
|
% endfor
|
|
% if f.is_varlen():
|
|
// 2nd case ${f.name}
|
|
*${f.name} = ${f.size('plen')} ? tal_arr(ctx, ${typename}, ${f.size('plen')}) : NULL;
|
|
% endif
|
|
% if f.len_field_of:
|
|
${f.name} = fromwire_${type_}(&cursor, &plen);
|
|
% elif f.type_obj.is_tlv():
|
|
fromwire_${f.type_obj.tlv.name}(&cursor, &plen, ${f.name});
|
|
% elif f.is_array() or f.is_varlen():
|
|
% if f.type_obj.has_array_helper():
|
|
fromwire_${type_}_array(&cursor, &plen, ${'*' if f.is_varlen() else ''}${f.name}, ${f.size('plen')});
|
|
% else:
|
|
% if f.is_implicit_len():
|
|
for (size_t i = 0; plen != 0; i++)
|
|
% else:
|
|
for (size_t i = 0; i < ${f.size()}; i++)
|
|
% endif
|
|
% if not varsized and not f.type_obj.is_assignable():
|
|
% if f.is_varlen():
|
|
fromwire_${type_}(&cursor, &plen, *${f.name} + i);
|
|
% else:
|
|
fromwire_${type_}(&cursor, &plen, &(${f.name}[i]));
|
|
% endif
|
|
% else:
|
|
(${'' if f.type_obj.is_assignable() and f.is_array() else '*'}${f.name})[i] = fromwire_${type_}(${'*'+f.name+', ' if varsized else ''}&cursor, &plen);
|
|
% endif
|
|
% endif
|
|
% else:
|
|
% if not f.is_optional:
|
|
${fromwire_phrase(f, type_, varsized)}\
|
|
% else: ## Start optional
|
|
if (!fromwire_bool(&cursor, &plen))
|
|
*${f.name} = NULL;
|
|
else {
|
|
% if not varsized:
|
|
*${f.name} = tal(ctx, ${typename});
|
|
% endif
|
|
${'*' if f.type_obj.is_assignable() else ''}${fromwire_phrase(f, type_, varsized)}\
|
|
}
|
|
% endif ## End optional
|
|
% endif
|
|
% endfor
|
|
return cursor != NULL;
|
|
}
|
|
% if msg.if_token:
|
|
#endif /* ${msg.if_token} */
|
|
% endif
|
|
% endfor ## END Wire Messages
|