Cloak/internal/multiplex/frameSorter.go

156 lines
4.1 KiB
Go
Raw Normal View History

2018-10-05 22:44:20 +00:00
package multiplex
import (
"container/heap"
2019-08-05 12:32:53 +00:00
"io"
log "github.com/sirupsen/logrus"
2018-10-05 22:44:20 +00:00
)
// The data is multiplexed through several TCP connections, therefore the
// order of arrival is not guaranteed. A stream's first packet may be sent through
// connection0 and its second packet may be sent through connection1. Although both
// packets are transmitted reliably (as TCP is reliable), packet1 may arrive to the
// remote side before packet0. Cloak have to therefore sequence the packets so that they
// arrive in order as they were sent by the proxy software
2018-10-05 22:44:20 +00:00
//
// Cloak packets will have a 32-bit sequence number on them, so we know in which order
// they should be sent to the proxy software. The code in this file provides buffering and sorting.
2018-10-05 22:44:20 +00:00
//
// Similar to TCP, the next seq number after 2^32-1 is 0. This is called wrap around.
//
// Note that in golang, integer overflow results in wrap around
//
// Stream.nextRecvSeq is the expected sequence number of the next packet
// Stream.rev counts the amount of time the sequence number gets wrapped
type frameNode struct {
2019-01-13 19:06:12 +00:00
trueSeq uint64
frame *Frame
2018-10-05 22:44:20 +00:00
}
type sorterHeap []*frameNode
func (sh sorterHeap) Less(i, j int) bool {
2019-01-13 19:06:12 +00:00
return sh[i].trueSeq < sh[j].trueSeq
2018-10-05 22:44:20 +00:00
}
func (sh sorterHeap) Len() int {
return len(sh)
}
func (sh sorterHeap) Swap(i, j int) {
sh[i], sh[j] = sh[j], sh[i]
}
func (sh *sorterHeap) Push(x interface{}) {
*sh = append(*sh, x.(*frameNode))
}
func (sh *sorterHeap) Pop() interface{} {
old := *sh
n := len(old)
x := old[n-1]
*sh = old[0 : n-1]
return x
}
2019-08-05 12:32:53 +00:00
type frameSorter struct {
nextRecvSeq uint32
rev int
sh sorterHeap
wrapMode bool
// New frames are received through newFrameCh by frameSorter
newFrameCh chan *Frame
output io.WriteCloser
}
func NewFrameSorter(output io.WriteCloser) *frameSorter {
fs := &frameSorter{
sh: []*frameNode{},
newFrameCh: make(chan *Frame, 1024),
rev: 0,
output: output,
}
go fs.recvNewFrame()
return fs
}
func (fs *frameSorter) writeNewFrame(f *Frame) {
fs.newFrameCh <- f
}
func (fs *frameSorter) Close() error {
fs.newFrameCh <- nil
return nil
2018-11-07 21:16:13 +00:00
}
// recvNewFrame is a forever running loop which receives frames unordered,
// cache and order them and send them into sortedBufCh
2019-08-05 12:32:53 +00:00
func (fs *frameSorter) recvNewFrame() {
defer log.Tracef("a recvNewFrame has returned gracefully")
2018-10-09 20:53:55 +00:00
for {
2019-08-05 12:32:53 +00:00
f := <-fs.newFrameCh
2019-07-28 10:58:45 +00:00
if f == nil {
2018-10-27 14:27:43 +00:00
return
2018-10-09 20:53:55 +00:00
}
2018-10-16 20:13:19 +00:00
2019-08-05 12:32:53 +00:00
// when there'fs no ooo packages in heap and we receive the next package in order
if len(fs.sh) == 0 && f.Seq == fs.nextRecvSeq {
2019-01-19 19:30:00 +00:00
if f.Closing == 1 {
// empty data indicates closing signal
2019-08-05 12:32:53 +00:00
fs.output.Close()
2019-01-19 19:30:00 +00:00
return
} else {
2019-08-05 12:32:53 +00:00
fs.output.Write(f.Payload)
fs.nextRecvSeq += 1
if fs.nextRecvSeq == 0 { // getting wrapped
fs.rev += 1
fs.wrapMode = false
}
2019-01-19 19:30:00 +00:00
}
2018-10-20 16:03:39 +00:00
continue
}
2019-08-05 12:32:53 +00:00
node := &frameNode{
2019-01-13 19:06:12 +00:00
trueSeq: 0,
frame: f,
}
2019-08-05 12:32:53 +00:00
if f.Seq < fs.nextRecvSeq {
2019-01-13 19:06:12 +00:00
// For the ease of demonstration, assume seq is uint8, i.e. it wraps around after 255
// e.g. we are on rev=0 (wrap has not happened yet)
// and we get the order of recv as 253 254 0 1
// after 254, nextN should be 255, but 0 is received and 0 < 255
// now 0 should have a trueSeq of 256
2019-08-05 12:32:53 +00:00
if !fs.wrapMode {
2019-01-13 19:06:12 +00:00
// wrapMode is true when the latest seq is wrapped but nextN is not
2019-08-05 12:32:53 +00:00
fs.wrapMode = true
2019-01-13 19:06:12 +00:00
}
2019-08-05 12:32:53 +00:00
node.trueSeq = uint64(1<<32)*uint64(fs.rev+1) + uint64(f.Seq) + 1
2019-01-13 19:06:12 +00:00
// +1 because wrapped 0 should have trueSeq of 256 instead of 255
// when this bit was run on 1, the trueSeq of 1 would become 256
} else {
2019-08-05 12:32:53 +00:00
node.trueSeq = uint64(1<<32)*uint64(fs.rev) + uint64(f.Seq)
2019-01-13 19:06:12 +00:00
// when this bit was run on 255, the trueSeq of 255 would be 255
2018-10-09 20:53:55 +00:00
}
2018-10-05 22:44:20 +00:00
2019-08-05 12:32:53 +00:00
heap.Push(&fs.sh, node)
2018-10-09 20:53:55 +00:00
// Keep popping from the heap until empty or to the point that the wanted seq was not received
2019-08-05 12:32:53 +00:00
for len(fs.sh) > 0 && fs.sh[0].frame.Seq == fs.nextRecvSeq {
f = heap.Pop(&fs.sh).(*frameNode).frame
if f.Closing == 1 {
2019-01-19 19:30:00 +00:00
// empty data indicates closing signal
2019-08-05 12:32:53 +00:00
fs.output.Close()
2019-01-19 19:30:00 +00:00
return
} else {
2019-08-05 12:32:53 +00:00
fs.output.Write(f.Payload)
fs.nextRecvSeq += 1
if fs.nextRecvSeq == 0 { // getting wrapped
fs.rev += 1
fs.wrapMode = false
}
2019-01-19 19:30:00 +00:00
}
2018-10-05 22:44:20 +00:00
}
}
}