/
routines.go
158 lines (146 loc) · 3.21 KB
/
routines.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
package boxtransport
import (
"crypto/rand"
"encoding/binary"
"errors"
"golang.org/x/crypto/nacl/box"
"time"
)
/*
Contains helper structures and methods not visible outside the package.
Primarily reading and writing routines.
*/
type writeRequest struct {
msg []byte
n chan int
}
// Frames raw data and writes to socket
func (c *BoxConn) boxWriter() {
tmp := make([]byte, MaxRawData+LenFieldSize)
for msg, ok := <-c.outBox; ok; msg, ok = <-c.outBox {
size := len(msg)
tmp = tmp[:size+LenFieldSize]
binary.BigEndian.PutUint16(tmp[:LenFieldSize], uint16(size))
copy(tmp[LenFieldSize:], msg)
for left := tmp; len(left) > 0; {
n, err := c.conn.Write(left)
if err != nil {
c.errors <- err
return
}
left = left[n:]
}
}
}
// Reads from socket and extracts raw data from frames
func (c *BoxConn) boxReader() {
buff := make([]byte, MaxRawData+LenFieldSize)
buffSize := 0
defer func() {
recover()
}()
for {
// Extract data
if buffSize >= LenFieldSize {
frameSize := int(binary.BigEndian.Uint16(buff[:])) + LenFieldSize
if buffSize >= frameSize {
tmp := make([]byte, frameSize-LenFieldSize)
copy(tmp, buff[LenFieldSize:frameSize])
copy(buff, buff[frameSize:buffSize])
buffSize -= frameSize
c.inBox <- tmp
continue
}
}
// Read more data
n, err := c.conn.Read(buff[buffSize:])
buffSize += n
if err != nil {
c.errors <- err
return
}
}
}
// Adds opportunistic buffering to boxWriter
func (c *BoxConn) streamWriter() {
frameSize := 0
frame := make([]byte, MaxContent)
var encMsg []byte
var err error
var ok bool
var req *writeRequest
defer func() {
recover()
}()
for {
// Read next request or attempt socket write
if req == nil && len(encMsg) != 0 {
select {
case req, ok = <-c.outStream:
if !ok {
return
}
case c.outBox <- encMsg:
encMsg = nil
frameSize = 0
}
} else if len(encMsg) != 0 {
c.outBox <- encMsg
encMsg = nil
frameSize = 0
} else {
req, ok = <-c.outStream
if !ok {
return
}
}
// Copy data into frame
if req != nil && MaxContent-frameSize > 0 {
n := copy(frame[frameSize:], req.msg)
req.n <- n
req.msg = req.msg[n:]
frameSize += n
encMsg = nil
if len(req.msg) == 0 {
req = nil
}
}
// Wait a little for more content (if needed)
if MaxContent-frameSize > 0 {
if len(c.outStream) > 0 {
continue
}
time.Sleep(c.holdTime)
if len(c.outStream) > 0 {
continue
}
}
// Seal message to send
if frameSize > 0 && encMsg == nil {
encMsg, err = c.seal(frame[:frameSize])
if err != nil {
c.errors <- err
return
}
}
}
}
// Seals data
func (c *BoxConn) seal(b []byte) ([]byte, error) {
var nonce [NonceSize]byte
n, err := rand.Read(nonce[:])
if err != nil || n != NonceSize {
return nil, errors.New("Failed to generate nonce")
}
return box.SealAfterPrecomputation(nonce[:], b, &nonce, c.sharedSecret), nil
}
// Unseals and verifies data
func (c *BoxConn) unseal(b []byte) ([]byte, error) {
var nonce [NonceSize]byte
copy(nonce[:], b[:NonceSize])
plain, valid := box.OpenAfterPrecomputation(nil, b[NonceSize:], &nonce, c.sharedSecret)
if !valid {
return nil, errors.New("Recieved invalid box")
}
return plain, nil
}