-
Notifications
You must be signed in to change notification settings - Fork 4
/
handshake.go
199 lines (172 loc) · 4.14 KB
/
handshake.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
package rtmp
import (
"bufio"
"bytes"
"errors"
"github.com/torresjeff/rtmp/rand"
"io"
)
var ErrUnsupportedRTMPVersion error = errors.New("The version of RTMP is not supported")
var ErrWrongC2Message error = errors.New("server handshake: s1 and c2 handshake messages do not match")
var ErrWrongS2Message error = errors.New("client handshake: c1 and s2 handshake messages do not match")
var ErrHandshakeAlreadyCompleted error = errors.New("invalid call to perform handshake, attempted to perform " +
"handshake more than once")
const RtmpVersion3 = 3
type Handshaker struct {
reader *bufio.Reader
writer *bufio.Writer
handshakeCompleted bool
}
func NewHandshaker(reader *bufio.Reader, writer *bufio.Writer) *Handshaker {
return &Handshaker{
reader,
writer,
false,
}
}
func (h *Handshaker) Handshake() error {
if h.handshakeCompleted {
return ErrHandshakeAlreadyCompleted
}
c1, err := h.readC0C1()
if err != nil {
return err
}
s1, err := h.sendS0S1S2(c1)
if err != nil {
return err
}
c2, err := h.readC2()
if err != nil {
return err
}
if bytes.Compare(s1, c2) != 0 {
return ErrWrongC2Message
}
h.handshakeCompleted = true
return nil
}
func (h *Handshaker) ClientHandshake() error {
if h.handshakeCompleted {
return ErrHandshakeAlreadyCompleted
}
c1, err := h.sendC0C1()
if err != nil {
return err
}
s1, s2, err := h.readS0S1S2()
if err != nil {
return err
}
if bytes.Compare(c1, s2) != 0 {
return ErrWrongS2Message
}
err = h.sendC2(s1)
if err != nil {
return err
}
h.handshakeCompleted = true
return nil
}
func (h *Handshaker) sendC2(s1 []byte) error {
var c2 [1536]byte
err := h.generateEcho(c2[:], s1)
if err != nil {
return err
}
err = h.send(c2[:])
if err != nil {
return err
}
return nil
}
// Returns s1 and s2
func (h *Handshaker) readS0S1S2() ([]byte, []byte, error) {
var s0s1s2 [1 + 2*1536]byte
if _, err := io.ReadFull(h.reader, s0s1s2[:]); err != nil {
return nil, nil, err
}
if s0s1s2[0] != RtmpVersion3 {
return nil, nil, ErrUnsupportedRTMPVersion
}
// Return s1, s2, and nil error
return s0s1s2[1:1537], s0s1s2[1537:], nil
}
// Returns the C1 message that was sent
func (h *Handshaker) sendC0C1() ([]byte, error) {
var c0c1 [1537]byte
// c0
c0c1[0] = RtmpVersion3
// c1
err := h.generateRandomData(c0c1[1:])
if err != nil {
return nil, err
}
err = h.send(c0c1[:])
if err != nil {
return nil, err
}
return c0c1[1:], nil
}
// If successful returns the C1 handshake data (random data sent by the client), it does not return c0 + c1.
func (h *Handshaker) readC0C1() ([]byte, error) {
var c0c1 [1537]byte
if _, err := io.ReadFull(h.reader, c0c1[:]); err != nil {
return nil, err
}
if c0c1[0] != RtmpVersion3 {
return nil, ErrUnsupportedRTMPVersion
}
// Returns c1 message
return c0c1[1:], nil
}
// Returns the C2 message
func (h *Handshaker) readC2() ([]byte, error) {
var c2 [1536]byte
if _, err := io.ReadFull(h.reader, c2[:]); err != nil {
return nil, err
}
return c2[:], nil
}
// Sends the s0, s1, and s2 sequence and returns the s1 message that was generated
func (h *Handshaker) sendS0S1S2(c1 []byte) ([]byte, error) {
var s0s1s2 [1 + 2*1536]byte
var err error
// s0 message is stored in byte 0
s0s1s2[0] = RtmpVersion3
// s1 message is stored in bytes 1-1536
if err = h.generateRandomData(s0s1s2[1:1537]); err != nil {
return nil, err
}
// s2 message is stored in bytes 1537-3073
if err = h.generateEcho(s0s1s2[1537:], c1); err != nil {
return nil, err
}
err = h.send(s0s1s2[:])
if err != nil {
return nil, err
}
return s0s1s2[1:1537], nil
}
// Generates an S1 message (random data)
func (h *Handshaker) generateRandomData(s1 []byte) error {
// the s1 byte array is zero-initialized, since we didn't modify it, we're sending our time as 0
err := rand.GenerateCryptoSafeRandomData(s1[8:])
if err != nil {
return err
}
return nil
}
func (h *Handshaker) generateEcho(target []byte, source []byte) error {
copy(target[:], source)
return nil
}
func (h *Handshaker) send(bytes []byte) error {
if _, err := h.writer.Write(bytes); err != nil {
return err
}
if err := h.writer.Flush(); err != nil {
return err
}
return nil
}