-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathrdr.go
116 lines (100 loc) · 3.31 KB
/
rdr.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
// Package rdr implements Realtime Data Retrieval (RDR) protocol.
// https://redmine.named-data.net/projects/ndn-tlv/wiki/RDR
package rdr
import (
"context"
"encoding"
"errors"
"fmt"
"github.com/usnistgov/ndn-dpdk/ndn"
"github.com/usnistgov/ndn-dpdk/ndn/an"
"github.com/usnistgov/ndn-dpdk/ndn/endpoint"
"github.com/usnistgov/ndn-dpdk/ndn/tlv"
)
// KeywordMetadata is the 32=metadata component.
var KeywordMetadata = ndn.MakeNameComponent(an.TtKeywordNameComponent, []byte("metadata"))
// MakeDiscoveryInterest creates an RDR discovery Interest.
// KeywordMetadata is appended automatically if it does not exist.
func MakeDiscoveryInterest(prefix ndn.Name) ndn.Interest {
if !prefix[len(prefix)-1].Equal(KeywordMetadata) {
prefix = prefix.Append(KeywordMetadata)
}
return ndn.Interest{
Name: prefix,
CanBePrefix: true,
MustBeFresh: true,
}
}
// IsDiscoveryInterest determines whether an Interest is an RDR discovery Interest.
func IsDiscoveryInterest(interest ndn.Interest) bool {
return len(interest.Name) > 1 && interest.Name[len(interest.Name)-1].Equal(KeywordMetadata) &&
interest.CanBePrefix && interest.MustBeFresh
}
// RetrieveMetadata retrieves RDR metadata.
//
// m: either *Metadata or its derived type.
func RetrieveMetadata(ctx context.Context, m encoding.BinaryUnmarshaler, name ndn.Name, opts endpoint.ConsumerOptions) error {
interest := MakeDiscoveryInterest(name)
data, e := endpoint.Consume(ctx, interest, opts)
if e != nil {
return e
}
if data.ContentType != an.ContentBlob {
return ndn.ErrContentType
}
return m.UnmarshalBinary(data.Content)
}
// Metadata contains RDR metadata packet content.
type Metadata struct {
Name ndn.Name
}
var (
_ encoding.BinaryMarshaler = Metadata{}
_ encoding.BinaryUnmarshaler = (*Metadata)(nil)
)
// MarshalBinary encodes to TLV-VALUE.
func (m Metadata) MarshalBinary() (value []byte, e error) {
return m.Encode()
}
// Encode encodes to TLV-VALUE with extensions.
func (m Metadata) Encode(extensions ...tlv.Fielder) (value []byte, e error) {
return tlv.EncodeFrom(append([]tlv.Fielder{m.Name}, extensions...)...)
}
// UnmarshalBinary decodes from TLV-VALUE.
func (m *Metadata) UnmarshalBinary(value []byte) error {
return m.Decode(value, nil)
}
// Decode decodes from TLV-VALUE with extensions.
func (m *Metadata) Decode(value []byte, extensions MetadataDecoderMap) error {
*m = Metadata{}
d := tlv.DecodingBuffer(value)
hasName := false
for de := range d.IterElements() {
var f MetadataFieldDecoder
if de.Type == an.TtName && !hasName {
f = m.decodeName
hasName = true
} else if f = extensions[de.Type]; f != nil {
// use extension decoder for TLV-TYPE
} else if f = extensions[0]; f != nil {
// use general extension decoder
} else {
// ignore unknown field
continue
}
if e := f(de); e != nil {
return fmt.Errorf("TLV-TYPE 0x%02x: %w", de.Type, e)
}
}
if !hasName {
return errors.New("missing Name in RDR metadata")
}
return d.ErrUnlessEOF()
}
func (m *Metadata) decodeName(de tlv.DecodingElement) error {
return de.UnmarshalValue(&m.Name)
}
// MetadataFieldDecoder is a callback function to decode a Metadata extension TLV.
type MetadataFieldDecoder func(de tlv.DecodingElement) error
// MetadataDecoderMap is a set of MetadataFieldDecoders where each key is a TLV-TYPE.
type MetadataDecoderMap map[uint32]MetadataFieldDecoder