~fnux/yggdrasil-go-coap

ref: e042d7baf5169b5c24e7261d57260a87506cb2db yggdrasil-go-coap/messagedgram.go -rw-r--r-- 3.0 KiB
e042d7ba — Jozef Kralik fix sending message when peerMaxMessageSize is not set 2 years ago
                                                                                
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
package coap

import (
	"bytes"
	"encoding/binary"
	"io"
	"sort"
)

// DgramMessage implements Message interface.
type DgramMessage struct {
	MessageBase
}

func NewDgramMessage(p MessageParams) *DgramMessage {
	return &DgramMessage{
		MessageBase{
			typ:       p.Type,
			code:      p.Code,
			messageID: p.MessageID,
			token:     p.Token,
			payload:   p.Payload,
		},
	}
}

// SetMessageID
func (m *DgramMessage) SetMessageID(messageID uint16) {
	m.messageID = messageID
}

// MarshalBinary produces the binary form of this DgramMessage.
func (m *DgramMessage) MarshalBinary(buf io.Writer) error {
	tmpbuf := []byte{0, 0}
	binary.BigEndian.PutUint16(tmpbuf, m.MessageID())

	/*
	     0                   1                   2                   3
	    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   |Ver| T |  TKL  |      Code     |          Message ID           |
	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   |   Token (if any, TKL bytes) ...
	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   |   Options (if any) ...
	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   |1 1 1 1 1 1 1 1|    Payload (if any) ...
	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	*/

	buf.Write([]byte{
		(1 << 6) | (uint8(m.Type()) << 4) | uint8(0xf&len(m.MessageBase.token)),
		byte(m.MessageBase.code),
		tmpbuf[0], tmpbuf[1],
	})

	if len(m.MessageBase.token) > MaxTokenSize {
		return ErrInvalidTokenLen
	}
	buf.Write(m.MessageBase.token)

	sort.Stable(&m.MessageBase.opts)
	writeOpts(buf, m.MessageBase.opts)

	if len(m.MessageBase.payload) > 0 {
		buf.Write([]byte{0xff})
	}

	buf.Write(m.MessageBase.payload)

	return nil
}

// UnmarshalBinary parses the given binary slice as a DgramMessage.
func (m *DgramMessage) UnmarshalBinary(data []byte) error {
	if len(data) < 4 {
		return ErrMessageTruncated
	}

	if data[0]>>6 != 1 {
		return ErrMessageInvalidVersion
	}

	m.MessageBase.typ = COAPType((data[0] >> 4) & 0x3)
	tokenLen := int(data[0] & 0xf)
	if tokenLen > 8 {
		return ErrInvalidTokenLen
	}

	m.MessageBase.code = COAPCode(data[1])
	m.MessageBase.messageID = binary.BigEndian.Uint16(data[2:4])

	if tokenLen > 0 {
		m.MessageBase.token = make([]byte, tokenLen)
	}
	if len(data) < 4+tokenLen {
		return ErrMessageTruncated
	}
	copy(m.MessageBase.token, data[4:4+tokenLen])
	b := data[4+tokenLen:]

	o, p, err := parseBody(coapOptionDefs, b)
	if err != nil {
		return err
	}

	m.MessageBase.payload = p
	m.MessageBase.opts = o

	return nil
}

// ParseDgramMessage extracts the Message from the given input.
func ParseDgramMessage(data []byte) (*DgramMessage, error) {
	rv := &DgramMessage{}
	return rv, rv.UnmarshalBinary(data)
}

// ToBytesLength gets the length of the message
func (m *DgramMessage) ToBytesLength() (int, error) {
	buf := bytes.NewBuffer(make([]byte, 0, 1024))
	if err := m.MarshalBinary(buf); err != nil {
		return 0, err
	}

	return len(buf.Bytes()), nil
}