forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtlvstream.c
168 lines (151 loc) · 3.88 KB
/
tlvstream.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#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-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #1:
* - if a `type` or `length` is not minimally encoded:
* - MUST fail to parse the `tlv_stream`.
*/
if (!*cursor) {
SUPERVERBOSE("length");
goto fail;
}
/* BOLT-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #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-EXPERIMENTAL #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);
}
}