mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
0da074cad3
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
169 lines
3.8 KiB
C
169 lines
3.8 KiB
C
#include "wire/tlvstream.h"
|
|
#include <assert.h>
|
|
#include <wire/wire.h>
|
|
|
|
#ifndef SUPERVERBOSE
|
|
#define SUPERVERBOSE(...)
|
|
#endif
|
|
|
|
static const struct tlv_record_type *
|
|
find_record_type(u64 type,
|
|
const struct tlv_record_type types[],
|
|
size_t num_types)
|
|
{
|
|
for (size_t i = 0; i < num_types; i++)
|
|
if (types[i].type == type)
|
|
return types + i;
|
|
return NULL;
|
|
}
|
|
|
|
/* Pull all tlvs from a stream. Return false and calls fromwire_fail() on
|
|
* error. */
|
|
bool fromwire_tlvs(const u8 **cursor, size_t *max,
|
|
const struct tlv_record_type types[],
|
|
size_t num_types,
|
|
void *record)
|
|
{
|
|
/* prev_type points to prev_type_store after first iter. */
|
|
u64 prev_type_store, *prev_type = NULL;
|
|
|
|
/* BOLT #1:
|
|
*
|
|
* The receiving node:
|
|
* - if zero bytes remain before parsing a `type`:
|
|
* - MUST stop parsing the `tlv_stream`.
|
|
*/
|
|
while (*max > 0) {
|
|
u64 type, length;
|
|
const struct tlv_record_type *rtype;
|
|
|
|
/* BOLT #1:
|
|
*
|
|
* A `varint` is a variable-length, unsigned integer encoding
|
|
* using the [BigSize](#appendix-a-bigsize-test-vectors)
|
|
* format
|
|
*/
|
|
type = 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;
|
|
}
|
|
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 (length > *max) {
|
|
SUPERVERBOSE("value");
|
|
goto fail;
|
|
}
|
|
|
|
/* BOLT #1:
|
|
* - if decoded `type`s are not monotonically-increasing:
|
|
* - MUST fail to parse the `tlv_stream`.
|
|
*/
|
|
if (prev_type && type <= *prev_type) {
|
|
if (type == *prev_type)
|
|
SUPERVERBOSE("duplicate tlv type");
|
|
else
|
|
SUPERVERBOSE("invalid ordering");
|
|
goto fail;
|
|
}
|
|
|
|
/* BOLT #1:
|
|
* - if `type` is known:
|
|
* - MUST decode the next `length` bytes using the known
|
|
* encoding for `type`.
|
|
*/
|
|
rtype = find_record_type(type, types, num_types);
|
|
if (rtype) {
|
|
/* Length of message can't exceed 16 bits anyway. */
|
|
size_t tlvlen = length;
|
|
rtype->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;
|
|
}
|
|
|
|
/* We've read bytes in ->fromwire, so update max */
|
|
*max -= length;
|
|
} else {
|
|
/* 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.
|
|
*/
|
|
if (type & 1)
|
|
fromwire(cursor, max, NULL, length);
|
|
else {
|
|
SUPERVERBOSE("unknown even");
|
|
goto fail;
|
|
}
|
|
}
|
|
prev_type = &prev_type_store;
|
|
*prev_type = type;
|
|
}
|
|
return true;
|
|
|
|
fail:
|
|
fromwire_fail(cursor, max);
|
|
return false;
|
|
}
|
|
|
|
/* Append a stream of tlvs. */
|
|
void towire_tlvs(u8 **pptr,
|
|
const struct tlv_record_type types[],
|
|
size_t num_types,
|
|
const void *record)
|
|
{
|
|
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);
|
|
}
|
|
}
|