-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathdata.go
353 lines (318 loc) · 9.09 KB
/
data.go
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
package ndn
import (
"crypto/sha256"
"encoding"
"math"
"reflect"
"time"
"github.com/usnistgov/ndn-dpdk/ndn/an"
"github.com/usnistgov/ndn-dpdk/ndn/tlv"
)
// Data represents a Data packet.
type Data struct {
packet *Packet
l3SigValueOffset int
Name Name
ContentType ContentType
Freshness time.Duration
FinalBlock NameComponent
Content []byte
SigInfo *SigInfo
SigValue []byte
}
var (
_ tlv.Fielder = Data{}
_ encoding.BinaryUnmarshaler = (*Data)(nil)
_ L3Packet = Data{}
)
// MakeData creates a Data from flexible arguments.
// Arguments can contain:
// - string or Name: set Name
// - ContentType
// - time.Duration: set Freshness
// - FinalBlock: set FinalBlock
// - FinalBlockFlag: set FinalBlock to the last name component, ignored if name is empty
// - []byte: set Content
// - LpL3: copy PitToken and CongMark
// - Interest or *Interest: copy Name, set FreshnessPeriod if Interest has MustBeFresh, inherit LpL3
func MakeData(args ...any) (data Data) {
data.packet = &Packet{}
hasFinalBlockFlag := false
handleInterestArg := func(a *Interest) {
data.Name = a.Name
if a.MustBeFresh {
data.Freshness = 1 * time.Millisecond
}
if ipkt := a.packet; ipkt != nil {
data.packet.Lp.inheritFrom(ipkt.Lp)
}
}
for _, arg := range args {
switch a := arg.(type) {
case string:
data.Name = ParseName(a)
case Name:
data.Name = a
case ContentType:
data.ContentType = a
case time.Duration:
data.Freshness = a
case FinalBlock:
data.FinalBlock = NameComponent(a)
case tFinalBlockFlag:
hasFinalBlockFlag = true
case []byte:
data.Content = a
case LpL3:
data.packet.Lp.inheritFrom(a)
case Interest:
handleInterestArg(&a)
case *Interest:
handleInterestArg(a)
default:
panic("bad argument type " + reflect.TypeOf(arg).String())
}
}
if hasFinalBlockFlag && len(data.Name) > 0 {
data.FinalBlock = data.Name.Get(-1)
}
return data
}
// ToPacket wraps Data as Packet.
func (data Data) ToPacket() (packet *Packet) {
packet = &Packet{}
if data.packet != nil {
*packet = *data.packet
}
packet.Data = &data
return packet
}
func (data Data) String() string {
return data.Name.String()
}
// ComputeDigest computes implicit digest of this Data.
//
// If data was decoded from Packet (data.packet is assigned), the digest is of the origin packet.
// Computed digest is cached on data.packet.
// Modifying a decoded Data will cause this function to return incorrect digest.
//
// If data was constructed (data.packet is unassigned), the digest is of the encoding of the current packet,
// and is not cached.
func (data Data) ComputeDigest() []byte {
var e error
if data.packet == nil {
data.packet = &Packet{Data: &data}
}
if data.packet.l3type != an.TtData {
if data.packet.l3value, e = tlv.EncodeValueOnly(data); e != nil {
return nil
}
data.packet.l3type = an.TtData
}
if data.packet.l3digest == nil {
wire, e := tlv.Encode(tlv.TLVBytes(an.TtData, data.packet.l3value))
if e != nil {
return nil
}
digest := sha256.Sum256(wire)
data.packet.l3digest = digest[:]
}
return data.packet.l3digest
}
// FullName returns full name of this Data.
func (data Data) FullName() Name {
fullName := make(Name, len(data.Name)+1)
i := copy(fullName, data.Name)
fullName[i] = MakeNameComponent(an.TtImplicitSha256DigestComponent, data.ComputeDigest())
return fullName
}
// IsFinalBlock determines whether FinalBlock field equals the last name component.
func (data Data) IsFinalBlock() bool {
return data.FinalBlock.Valid() && data.FinalBlock.Equal(data.Name.Get(-1))
}
// CanSatisfy determines whether this Data can satisfy the given Interest.
func (data Data) CanSatisfy(interest Interest, optionalFlag ...CanSatisfyFlag) bool {
var flag CanSatisfyFlag
if len(optionalFlag) == 1 {
flag = optionalFlag[0]
}
switch {
case len(interest.Name) == 0: // invalid Interest
return false
case flag&CanSatisfyInCache != 0 && interest.MustBeFresh && data.Freshness <= 0:
return false
case interest.Name[len(interest.Name)-1].Type == an.TtImplicitSha256DigestComponent:
return interest.Name.Equal(data.FullName())
case interest.CanBePrefix:
return interest.Name.IsPrefixOf(data.Name)
default:
return interest.Name.Equal(data.Name)
}
}
// SignWith implements Signable interface.
// Caller should use signer.Sign(data).
func (data *Data) SignWith(signer func(name Name, si *SigInfo) (LLSign, error)) error {
if data.SigInfo == nil {
data.SigInfo = newNullSigInfo()
}
llSign, e := signer(data.Name, data.SigInfo)
if e != nil {
return e
}
signedPortion, e := data.encodeSignedPortion()
if e != nil {
return e
}
sig, e := llSign(signedPortion)
if e != nil {
return e
}
data.SigValue = sig
return nil
}
// VerifyWith implements Verifiable interface.
// Caller should use verifier.Verify(data).
//
// If data was decoded from Packet (data.packet is assigned), verification is on the origin packet.
// Modifying a decoded Data will cause this function to return incorrect result.
//
// If data was constructed (data.packet is unassigned), verification is on the encoding of the current packet.
func (data Data) VerifyWith(verifier func(name Name, si SigInfo) (LLVerify, error)) error {
si := data.SigInfo
if si == nil {
si = newNullSigInfo()
}
llVerify, e := verifier(data.Name, *si)
if e != nil {
return e
}
var signedPortion []byte
if data.packet != nil && data.l3SigValueOffset > 0 {
signedPortion = data.packet.l3value[:data.l3SigValueOffset]
} else {
signedPortion, e = data.encodeSignedPortion()
if e != nil {
return e
}
}
return llVerify(signedPortion, data.SigValue)
}
// Field implements tlv.Fielder interface.
func (data Data) Field() tlv.Field {
signedPortion, e := data.encodeSignedPortion()
if e != nil {
return tlv.FieldError(e)
}
return tlv.TLV(an.TtData, tlv.Bytes(signedPortion), tlv.TLVBytes(an.TtDSigValue, data.SigValue))
}
// UnmarshalBinary decodes from TLV-VALUE.
func (data *Data) UnmarshalBinary(value []byte) (e error) {
*data = Data{}
d := tlv.DecodingBuffer(value)
for de := range d.IterElements() {
switch de.Type {
case an.TtName:
if e = de.UnmarshalValue(&data.Name); e != nil {
return e
}
case an.TtMetaInfo:
if e = data.decodeMetaInfo(de.Value); e != nil {
return e
}
case an.TtContent:
data.Content = de.Value
case an.TtDSigInfo:
var si SigInfo
if e = de.UnmarshalValue(&si); e != nil {
return e
}
data.SigInfo = &si
case an.TtDSigValue:
data.SigValue = de.Value
data.l3SigValueOffset = len(value) - len(de.WireAfter())
default:
if de.IsCriticalType() {
return tlv.ErrCritical
}
}
}
return d.ErrUnlessEOF()
}
func (data *Data) decodeMetaInfo(value []byte) (e error) {
d := tlv.DecodingBuffer(value)
for de := range d.IterElements() {
switch de.Type {
case an.TtContentType:
if data.ContentType = ContentType(de.UnmarshalNNI(math.MaxUint64, &e, tlv.ErrRange)); e != nil {
return e
}
case an.TtFreshnessPeriod:
if data.Freshness = time.Duration(de.UnmarshalNNI(uint64(math.MaxInt64/time.Millisecond), &e, tlv.ErrRange)); e != nil {
return e
}
data.Freshness *= time.Millisecond
case an.TtFinalBlock:
if data.FinalBlock, e = DecodeFinalBlock(de); e != nil {
return e
}
default:
if de.IsCriticalType() {
return tlv.ErrCritical
}
}
}
return d.ErrUnlessEOF()
}
func (data Data) encodeSignedPortion() (wire []byte, e error) {
fields := []tlv.Fielder{data.Name}
var metaFields []tlv.Field
if data.ContentType > 0 {
metaFields = append(metaFields, data.ContentType.Field())
}
if data.Freshness > 0 {
metaFields = append(metaFields, tlv.TLVNNI(an.TtFreshnessPeriod, data.Freshness/time.Millisecond))
}
if data.FinalBlock.Valid() {
metaFields = append(metaFields, tlv.TLVFrom(an.TtFinalBlock, data.FinalBlock))
}
if len(metaFields) > 0 {
fields = append(fields, tlv.TLV(an.TtMetaInfo, metaFields...))
}
if len(data.Content) > 0 {
fields = append(fields, tlv.TLVBytes(an.TtContent, data.Content))
}
fields = append(fields, data.SigInfo.EncodeAs(an.TtDSigInfo))
return tlv.EncodeFrom(fields...)
}
// ContentType represents a ContentType field.
type ContentType uint64
func (ct ContentType) Field() tlv.Field {
return tlv.TLVNNI(an.TtContentType, ct)
}
// UnmarshalBinary decodes from wire encoding.
func (ct *ContentType) UnmarshalBinary(wire []byte) error {
var n tlv.NNI
e := n.UnmarshalBinary(wire)
*ct = ContentType(n)
return e
}
// FinalBlock is passed to MakeData to set FinalBlock field.
type FinalBlock NameComponent
type tFinalBlockFlag bool
// FinalBlockFlag enables MakeData to set FinalBlock to the last name component.
const FinalBlockFlag = tFinalBlockFlag(true)
// DecodeFinalBlock decodes FinalBlock name component from FinalBlock TLV element.
func DecodeFinalBlock(de tlv.DecodingElement) (finalBlock NameComponent, e error) {
if e = tlv.Decode(de.Value, &finalBlock); e != nil {
return NameComponent{}, e
}
if !finalBlock.Valid() {
return NameComponent{}, ErrComponentType
}
return finalBlock, nil
}
// Data.CanSatisfy flags.
type CanSatisfyFlag int
const (
CanSatisfyInCache = 1 << iota
)