-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwire.go
166 lines (147 loc) · 3.83 KB
/
wire.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
package tftp
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
)
// larger than a typical mtu (1500), and largest DATA packet (516).
// may limit the length of filenames in RRQ/WRQs -- RFC1350 doesn't offer a bound for these.
const MaxPacketSize = 2048
const (
OpRRQ uint16 = 1
OpWRQ = 2
OpData = 3
OpAck = 4
OpError = 5
)
// packet is the interface met by all packet structs
type Packet interface {
// Parse parses a packet from its wire representation
Parse([]byte) error
// Serialize serializes a packet to its wire representation
Serialize() []byte
}
// PacketRequest represents a request to read or rite a file.
type PacketRequest struct {
Op uint16 // OpRRQ or OpWRQ
Filename string
Mode string
}
func (p *PacketRequest) Parse(buf []byte) (err error) {
if p.Op, buf, err = parseUint16(buf); err != nil {
return err
}
if p.Filename, buf, err = parseString(buf); err != nil {
return err
}
if p.Mode, buf, err = parseString(buf); err != nil {
return err
}
return nil
}
func (p *PacketRequest) Serialize() []byte {
buf := make([]byte, 2+len(p.Filename)+1+len(p.Mode)+1)
binary.BigEndian.PutUint16(buf, p.Op)
copy(buf[2:], p.Filename)
copy(buf[2+len(p.Filename)+1:], p.Mode)
return buf
}
// PacketData carries a block of data in a file transmission.
type PacketData struct {
BlockNum uint16
Data []byte
}
func (p *PacketData) Parse(buf []byte) (err error) {
buf = buf[2:] // skip over op
if p.BlockNum, buf, err = parseUint16(buf); err != nil {
return err
}
p.Data = buf
return nil
}
func (p *PacketData) Serialize() []byte {
buf := make([]byte, 4+len(p.Data))
binary.BigEndian.PutUint16(buf, OpData)
binary.BigEndian.PutUint16(buf[2:], p.BlockNum)
copy(buf[4:], p.Data)
return buf
}
// PacketAck acknowledges receipt of a data packet
type PacketAck struct {
BlockNum uint16
}
func (p *PacketAck) Parse(buf []byte) (err error) {
buf = buf[2:] // skip over op
if p.BlockNum, buf, err = parseUint16(buf); err != nil {
return err
}
return nil
}
func (p *PacketAck) Serialize() []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint16(buf, OpAck)
binary.BigEndian.PutUint16(buf[2:], p.BlockNum)
return buf
}
// PacketError is sent by a peer who has encountered an error condition
type PacketError struct {
Code uint16
Msg string
}
func (p *PacketError) Parse(buf []byte) (err error) {
buf = buf[2:] // skip over op
if p.Code, buf, err = parseUint16(buf); err != nil {
return err
}
if p.Msg, buf, err = parseString(buf); err != nil {
return err
}
return nil
}
func (p *PacketError) Serialize() []byte {
buf := make([]byte, 4+len(p.Msg)+1)
binary.BigEndian.PutUint16(buf, OpError)
binary.BigEndian.PutUint16(buf[2:], p.Code)
copy(buf[4:], p.Msg)
return buf
}
// parseUint16 reads a big-endian uint16 from the beginning of buf,
// returning it along with a slice pointing at the next position in the buffer.
func parseUint16(buf []byte) (uint16, []byte, error) {
if len(buf) < 2 {
return 0, nil, errors.New("packet truncated")
}
return binary.BigEndian.Uint16(buf), buf[2:], nil
}
// parseString reads a null-terminated ASCII string from buf,
// returning it along with a slice pointing at the next position in the buffer.
func parseString(buf []byte) (string, []byte, error) {
i := bytes.IndexByte(buf, 0)
if i < 0 {
return "", nil, errors.New("packet truncated")
}
return string(buf[:i]), buf[i+1:], nil
}
// ParsePacket parses a packet from its wire representation.
func ParsePacket(buf []byte) (p Packet, err error) {
var opcode uint16
if opcode, _, err = parseUint16(buf); err != nil {
return
}
switch opcode {
case OpRRQ, OpWRQ:
p = &PacketRequest{}
case OpData:
p = &PacketData{}
case OpAck:
p = &PacketAck{}
case OpError:
p = &PacketError{}
default:
err = fmt.Errorf("unexpected opcode %d", opcode)
return
}
err = p.Parse(buf)
return
}