/* 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 #include #include #include #include #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; } bool ${enum_set['name']}_is_defined(u16 type) { switch ((enum ${enum_set['name']})type) { % for msg in enum_set['set']: case ${msg.enum_name()}:; % endfor return true; } return false; } % 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 ## 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_array() or f.is_varlen(): % if f.type_obj.has_array_helper(): ## We assume array helpers only deal with things literally transcribed!! % if f.is_varlen(): ${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, ${f.size('*plen')}) : NULL; % endif fromwire_${type_}_array(cursor, plen, ${fieldname}, ${f.size('*plen')}); % else: % if f.is_varlen(): ${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, 0) : NULL; % endif % if f.is_implicit_len(): for (size_t i = 0; *plen != 0; i++) { % else: for (size_t i = 0; i < ${f.size()}; i++) { % endif ${typename} tmp; % if f.type_obj.is_assignable(): tmp = fromwire_${type_}(cursor, plen); % elif f.is_varlen() and f.type_obj.is_varsize(): tmp = fromwire_${type_}(${ctx}, cursor, plen); % else: fromwire_${type_}(cursor, plen, &tmp); % endif tal_arr_expand(&${fieldname}, tmp); } % 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 ## 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 % 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; ifields[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_${f.type_obj.tlv.name}(&p, ${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