package quic import ( "bytes" "fmt" "math" "math/rand" "time" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("frame sorter", func() { var s *frameSorter checkGaps := func(expectedGaps []utils.ByteInterval) { if s.gaps.Len() != len(expectedGaps) { fmt.Println("Gaps:") for gap := s.gaps.Front(); gap != nil; gap = gap.Next() { fmt.Printf("\t%d - %d\n", gap.Value.Start, gap.Value.End) } ExpectWithOffset(1, s.gaps.Len()).To(Equal(len(expectedGaps))) } var i int for gap := s.gaps.Front(); gap != nil; gap = gap.Next() { ExpectWithOffset(1, gap.Value).To(Equal(expectedGaps[i])) i++ } } type callbackTracker struct { called *bool cb func() } getCallback := func() (func(), callbackTracker) { var called bool cb := func() { if called { panic("double free") } called = true } return cb, callbackTracker{ cb: cb, called: &called, } } checkCallbackCalled := func(t callbackTracker) { ExpectWithOffset(1, *t.called).To(BeTrue()) } checkCallbackNotCalled := func(t callbackTracker) { ExpectWithOffset(1, *t.called).To(BeFalse()) t.cb() ExpectWithOffset(1, *t.called).To(BeTrue()) } BeforeEach(func() { s = newFrameSorter() }) It("returns nil when empty", func() { _, data, doneCb := s.Pop() Expect(data).To(BeNil()) Expect(doneCb).To(BeNil()) }) It("inserts and pops a single frame", func() { cb, t := getCallback() Expect(s.Push([]byte("foobar"), 0, cb)).To(Succeed()) offset, data, doneCb := s.Pop() Expect(offset).To(BeZero()) Expect(data).To(Equal([]byte("foobar"))) Expect(doneCb).ToNot(BeNil()) checkCallbackNotCalled(t) offset, data, doneCb = s.Pop() Expect(offset).To(Equal(protocol.ByteCount(6))) Expect(data).To(BeNil()) Expect(doneCb).To(BeNil()) }) It("inserts and pops two consecutive frame", func() { cb1, t1 := getCallback() cb2, t2 := getCallback() Expect(s.Push([]byte("bar"), 3, cb2)).To(Succeed()) Expect(s.Push([]byte("foo"), 0, cb1)).To(Succeed()) offset, data, doneCb := s.Pop() Expect(offset).To(BeZero()) Expect(data).To(Equal([]byte("foo"))) Expect(doneCb).ToNot(BeNil()) doneCb() checkCallbackCalled(t1) offset, data, doneCb = s.Pop() Expect(offset).To(Equal(protocol.ByteCount(3))) Expect(data).To(Equal([]byte("bar"))) Expect(doneCb).ToNot(BeNil()) doneCb() checkCallbackCalled(t2) offset, data, doneCb = s.Pop() Expect(offset).To(Equal(protocol.ByteCount(6))) Expect(data).To(BeNil()) Expect(doneCb).To(BeNil()) }) It("ignores empty frames", func() { Expect(s.Push(nil, 0, nil)).To(Succeed()) _, data, doneCb := s.Pop() Expect(data).To(BeNil()) Expect(doneCb).To(BeNil()) }) It("says if has more data", func() { Expect(s.HasMoreData()).To(BeFalse()) Expect(s.Push([]byte("foo"), 0, nil)).To(Succeed()) Expect(s.HasMoreData()).To(BeTrue()) _, data, _ := s.Pop() Expect(data).To(Equal([]byte("foo"))) Expect(s.HasMoreData()).To(BeFalse()) }) Context("Gap handling", func() { var dataCounter uint8 BeforeEach(func() { dataCounter = 0 }) checkQueue := func(m map[protocol.ByteCount][]byte) { ExpectWithOffset(1, s.queue).To(HaveLen(len(m))) for offset, data := range m { ExpectWithOffset(1, s.queue).To(HaveKey(offset)) ExpectWithOffset(1, s.queue[offset].Data).To(Equal(data)) } } getData := func(l protocol.ByteCount) []byte { dataCounter++ return bytes.Repeat([]byte{dataCounter}, int(l)) } // ---xxx-------------- // ++++++ // => // ---xxx++++++-------- It("case 1", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 11, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) }) // ---xxx----------------- // +++++++ // => // ---xxx---+++++++-------- It("case 2", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 -15 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 10: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 6, End: 10}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) }) // ---xxx----xxxxxx------- // ++++ // => // ---xxx++++xxxxx-------- It("case 3", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f2, 6, cb3)).To(Succeed()) // 6 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f2, 10: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ----xxxx------- // ++++ // => // ----xxxx++----- It("case 4", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7 Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 7: f2[2:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) It("case 4, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2)) f1 := getData(4 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 7 Expect(s.Push(f2, 5*mult, cb2)).To(Succeed()) // 5 - 9 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 7 * mult: f2[2*mult:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 9 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) }) // xxxx------- // ++++ // => // xxxx+++----- It("case 5", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 4 Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 7 checkQueue(map[protocol.ByteCount][]byte{ 0: f1, 4: f2[1:], }) checkGaps([]utils.ByteInterval{ {Start: 7, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) It("case 5, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2)) f1 := getData(4 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 4 Expect(s.Push(f2, 3*mult, cb2)).To(Succeed()) // 3 - 7 checkQueue(map[protocol.ByteCount][]byte{ 0: f1, 4 * mult: f2[mult:], }) checkGaps([]utils.ByteInterval{ {Start: 7 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) }) // ----xxxx------- // ++++ // => // --++xxxx------- It("case 6", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9 Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 7 checkQueue(map[protocol.ByteCount][]byte{ 3: f2[:2], 5: f1, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) It("case 6, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2)) f1 := getData(4 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() Expect(s.Push(f1, 5*mult, cb1)).To(Succeed()) // 5 - 9 Expect(s.Push(f2, 3*mult, cb2)).To(Succeed()) // 3 - 7 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f2[:2*mult], 5 * mult: f1, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 9 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) }) // ---xxx----xxxxxx------- // ++ // => // ---xxx++--xxxxx-------- It("case 7", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(2) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f2, 6, cb3)).To(Succeed()) // 6 - 8 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f2, 10: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 8, End: 10}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx---------xxxxxx-- // ++ // => // ---xxx---++----xxxxx-- It("case 8", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(2) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f3, 15, cb2)).To(Succeed()) // 15 - 20 Expect(s.Push(f2, 10, cb3)).To(Succeed()) // 10 - 12 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 10: f2, 15: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 6, End: 10}, {Start: 12, End: 15}, {Start: 20, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx----xxxxxx------- // ++ // => // ---xxx--++xxxxx-------- It("case 9", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(2) cb2, t2 := getCallback() cb3, t3 := getCallback() f3 := getData(5) Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f3, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f2, 8, cb3)).To(Succeed()) // 8 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 8: f2, 10: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 6, End: 8}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx----=====------- // +++++++ // => // ---xxx++++=====-------- It("case 10", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() f3 := getData(6) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f3[1:5], 10: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 10, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 4)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(5 * mult) cb2, t2 := getCallback() f3 := getData(6 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 10*mult, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 6 * mult: f3[mult : 5*mult], 10 * mult: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 15 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxxx----=====------- // ++++++ // => // ---xxx++++=====-------- It("case 11", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7 Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 7: f3[2:], 10: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) // ---xxxx----=====------- // ++++++ // => // ---xxx++++=====-------- It("case 11, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 3)) f1 := getData(4 * mult) cb1, t1 := getCallback() f2 := getData(5 * mult) cb2, t2 := getCallback() f3 := getData(5 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 7 Expect(s.Push(f2, 10*mult, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 7 * mult: f3[2*mult:], 10 * mult: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 15 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ----xxxx------- // +++++++ // => // ----+++++++----- It("case 12", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(7) cb2, t2 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 7 Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) }) // ----xxx===------- // +++++++ // => // ----+++++++----- It("case 13", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(7) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 10 checkQueue(map[protocol.ByteCount][]byte{ 3: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // ----xxx====------- // +++++ // => // ----+++====----- It("case 14", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 8 checkQueue(map[protocol.ByteCount][]byte{ 3: f3[:3], 6: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 14, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 3)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() f3 := getData(5 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 3*mult, cb3)).To(Succeed()) // 3 - 8 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f3[:3*mult], 6 * mult: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 10 * mult, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ----xxx===------- // ++++++ // => // ----++++++----- It("case 15", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(6) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 9 checkQueue(map[protocol.ByteCount][]byte{ 3: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // ---xxxx------- // ++++ // => // ---xxxx----- It("case 16", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9 Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9 checkQueue(map[protocol.ByteCount][]byte{ 5: f1, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 5}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) // ----xxx===------- // +++ // => // ----xxx===----- It("case 17", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(3) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 6 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) // ---xxxx------- // ++ // => // ---xxxx----- It("case 18", func() { f1 := getData(4) cb1, t1 := getCallback() f2 := getData(2) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 9 Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 7 checkQueue(map[protocol.ByteCount][]byte{ 5: f1, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 5}, {Start: 9, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) // ---xxxxx------ // ++ // => // ---xxxxx---- It("case 19", func() { f1 := getData(5) cb1, t1 := getCallback() f2 := getData(2) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10 checkQueue(map[protocol.ByteCount][]byte{ 5: f1, }) Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 8 checkQueue(map[protocol.ByteCount][]byte{ 5: f1, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 5}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) // xxxxx------ // ++ // => // xxxxx------ It("case 20", func() { f1 := getData(10) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() Expect(s.Push(f1, 0, cb1)).To(Succeed()) // 0 - 10 Expect(s.Push(f2, 5, cb2)).To(Succeed()) // 5 - 9 checkQueue(map[protocol.ByteCount][]byte{ 0: f1, }) checkGaps([]utils.ByteInterval{ {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) // ---xxxxx--- // +++ // => // ---xxxxx--- It("case 21", func() { f1 := getData(5) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10 Expect(s.Push(f2, 7, cb2)).To(Succeed()) // 7 - 10 checkGaps([]utils.ByteInterval{ {Start: 0, End: 5}, {Start: 10, End: protocol.MaxByteCount}, }) checkQueue(map[protocol.ByteCount][]byte{ 5: f1, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) }) // ----xxx------ // +++++ // => // --+++++---- It("case 22", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8 Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 8 checkQueue(map[protocol.ByteCount][]byte{ 3: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 8, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) }) // ----xxx===------ // ++++++++ // => // --++++++++---- It("case 23", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(8) cb3, t3 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8 Expect(s.Push(f2, 8, cb2)).To(Succeed()) // 8 - 11 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 11, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // --xxx---===--- // ++++++ // => // --xxx++++++---- It("case 24", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(6) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 6, cb3)).To(Succeed()) // 6 - 12 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 12, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // --xxx---===---### // +++++++++ // => // --xxx+++++++++### It("case 25", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(3) cb3, t3 := getCallback() f4 := getData(9) cb4, t4 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 15, cb3)).To(Succeed()) // 15 - 18 Expect(s.Push(f4, 6, cb4)).To(Succeed()) // 6 - 15 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f4, 15: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 18, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) checkCallbackNotCalled(t4) }) // ----xxx------ // +++++++ // => // --+++++++--- It("case 26", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(10) cb2, t2 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 8 Expect(s.Push(f2, 3, cb2)).To(Succeed()) // 3 - 13 checkQueue(map[protocol.ByteCount][]byte{ 3: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 13, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) }) // ---xxx====--- // ++++ // => // --+xxx====--- It("case 27", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() f3 := getData(4) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 2, cb3)).To(Succeed()) // 2 - 6 checkQueue(map[protocol.ByteCount][]byte{ 2: f3[:1], 3: f1, 6: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 2}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 27, for long frames", func() { const mult = protocol.MinStreamFrameSize f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() f3 := getData(4 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 2*mult, cb3)).To(Succeed()) // 2 - 6 checkQueue(map[protocol.ByteCount][]byte{ 2 * mult: f3[:mult], 3 * mult: f1, 6 * mult: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 2 * mult}, {Start: 10 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx====--- // ++++++ // => // --+xxx====--- It("case 28", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() f3 := getData(6) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 2, cb3)).To(Succeed()) // 2 - 8 checkQueue(map[protocol.ByteCount][]byte{ 2: f3[:1], 3: f1, 6: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 2}, {Start: 10, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 28, for long frames", func() { const mult = protocol.MinStreamFrameSize f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() f3 := getData(6 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 10 Expect(s.Push(f3, 2*mult, cb3)).To(Succeed()) // 2 - 8 checkQueue(map[protocol.ByteCount][]byte{ 2 * mult: f3[:mult], 3 * mult: f1, 6 * mult: f2, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 2 * mult}, {Start: 10 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx===----- // +++++ // => // ---xxx+++++--- It("case 29", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(5) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 6, cb3)).To(Succeed()) // 6 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 11, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx===---- // ++++++ // => // ---xxx===++-- It("case 30", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(6) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f2, 9: f3[4:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 11, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 30, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 2)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(3 * mult) cb2, t2 := getCallback() f3 := getData(6 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 6*mult, cb2)).To(Succeed()) // 6 - 9 Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 11 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 6 * mult: f2, 9 * mult: f3[4*mult:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 11 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx---===----- // ++++++++++ // => // ---xxx++++++++--- It("case 31", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(10) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 5, cb3)).To(Succeed()) // 5 - 15 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f3[1:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 15, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackCalled(t3) }) It("case 31, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 9)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(3 * mult) cb2, t2 := getCallback() f3 := getData(10 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 5*mult, cb3)).To(Succeed()) // 5 - 15 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 6 * mult: f3[mult:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 15 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx---===----- // +++++++++ // => // ---+++++++++--- It("case 32", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(9) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 12 checkQueue(map[protocol.ByteCount][]byte{ 3: f3, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 12, End: protocol.MaxByteCount}, }) checkCallbackCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) }) // ---xxx---===###----- // ++++++++++++ // => // ---xxx++++++++++--- It("case 33", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(3) cb2, t2 := getCallback() f3 := getData(3) cb3, t3 := getCallback() f4 := getData(12) cb4, t4 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 9, cb3)).To(Succeed()) // 12 - 15 Expect(s.Push(f4, 5, cb4)).To(Succeed()) // 5 - 17 checkQueue(map[protocol.ByteCount][]byte{ 3: f1, 6: f4[1:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 17, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackCalled(t3) checkCallbackCalled(t4) }) It("case 33, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 11)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(3 * mult) cb2, t2 := getCallback() f3 := getData(3 * mult) cb3, t3 := getCallback() f4 := getData(12 * mult) cb4, t4 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 12 Expect(s.Push(f3, 9*mult, cb3)).To(Succeed()) // 12 - 15 Expect(s.Push(f4, 5*mult, cb4)).To(Succeed()) // 5 - 17 checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f1, 6 * mult: f4[mult:], }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 17 * mult, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackCalled(t3) checkCallbackNotCalled(t4) }) // ---xxx===---### // ++++++ // => // ---xxx++++++### It("case 34", func() { f1 := getData(5) cb1, t1 := getCallback() f2 := getData(5) cb2, t2 := getCallback() f3 := getData(10) cb3, t3 := getCallback() f4 := getData(5) cb4, t4 := getCallback() Expect(s.Push(f1, 5, cb1)).To(Succeed()) // 5 - 10 Expect(s.Push(f2, 10, cb2)).To(Succeed()) // 10 - 15 Expect(s.Push(f4, 20, cb3)).To(Succeed()) // 20 - 25 Expect(s.Push(f3, 10, cb4)).To(Succeed()) // 10 - 20 checkQueue(map[protocol.ByteCount][]byte{ 5: f1, 10: f3, 20: f4, }) checkGaps([]utils.ByteInterval{ {Start: 0, End: 5}, {Start: 25, End: protocol.MaxByteCount}, }) checkCallbackNotCalled(t1) checkCallbackCalled(t2) checkCallbackNotCalled(t3) checkCallbackNotCalled(t4) }) // ---xxx---####--- // ++++++++ // => // ---++++++####--- It("case 35", func() { f1 := getData(3) cb1, t1 := getCallback() f2 := getData(4) cb2, t2 := getCallback() f3 := getData(8) cb3, t3 := getCallback() Expect(s.Push(f1, 3, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9, cb2)).To(Succeed()) // 9 - 13 Expect(s.Push(f3, 3, cb3)).To(Succeed()) // 3 - 11 checkGaps([]utils.ByteInterval{ {Start: 0, End: 3}, {Start: 13, End: protocol.MaxByteCount}, }) checkQueue(map[protocol.ByteCount][]byte{ 3: f3[:6], 9: f2, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) checkCallbackCalled(t3) }) It("case 35, for long frames", func() { mult := protocol.ByteCount(math.Ceil(float64(protocol.MinStreamFrameSize) / 6)) f1 := getData(3 * mult) cb1, t1 := getCallback() f2 := getData(4 * mult) cb2, t2 := getCallback() f3 := getData(8 * mult) cb3, t3 := getCallback() Expect(s.Push(f1, 3*mult, cb1)).To(Succeed()) // 3 - 6 Expect(s.Push(f2, 9*mult, cb2)).To(Succeed()) // 9 - 13 Expect(s.Push(f3, 3*mult, cb3)).To(Succeed()) // 3 - 11 checkGaps([]utils.ByteInterval{ {Start: 0, End: 3 * mult}, {Start: 13 * mult, End: protocol.MaxByteCount}, }) checkQueue(map[protocol.ByteCount][]byte{ 3 * mult: f3[:6*mult], 9 * mult: f2, }) checkCallbackCalled(t1) checkCallbackNotCalled(t2) checkCallbackNotCalled(t3) }) Context("receiving data after reads", func() { It("ignores duplicate frames", func() { Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed()) offset, data, _ := s.Pop() Expect(offset).To(BeZero()) Expect(data).To(Equal([]byte("foobar"))) // now receive the duplicate Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed()) Expect(s.queue).To(BeEmpty()) checkGaps([]utils.ByteInterval{ {Start: 6, End: protocol.MaxByteCount}, }) }) It("ignores parts of frames that have already been read", func() { Expect(s.Push([]byte("foo"), 0, nil)).To(Succeed()) offset, data, _ := s.Pop() Expect(offset).To(BeZero()) Expect(data).To(Equal([]byte("foo"))) // now receive the duplicate Expect(s.Push([]byte("foobar"), 0, nil)).To(Succeed()) offset, data, _ = s.Pop() Expect(offset).To(Equal(protocol.ByteCount(3))) Expect(data).To(Equal([]byte("bar"))) Expect(s.queue).To(BeEmpty()) checkGaps([]utils.ByteInterval{ {Start: 6, End: protocol.MaxByteCount}, }) }) }) Context("DoS protection", func() { It("errors when too many gaps are created", func() { for i := 0; i < protocol.MaxStreamFrameSorterGaps; i++ { Expect(s.Push([]byte("foobar"), protocol.ByteCount(i*7), nil)).To(Succeed()) } Expect(s.gaps.Len()).To(Equal(protocol.MaxStreamFrameSorterGaps)) err := s.Push([]byte("foobar"), protocol.ByteCount(protocol.MaxStreamFrameSorterGaps*7)+100, nil) Expect(err).To(MatchError("too many gaps in received data")) }) }) }) Context("stress testing", func() { type frame struct { offset protocol.ByteCount data []byte } for _, lf := range []bool{true, false} { longFrames := lf const num = 1000 name := "short" if longFrames { name = "long" } Context(fmt.Sprintf("using %s frames", name), func() { var data []byte var dataLen protocol.ByteCount var callbacks []callbackTracker BeforeEach(func() { seed := time.Now().UnixNano() fmt.Fprintf(GinkgoWriter, "Seed: %d\n", seed) rand.Seed(seed) callbacks = nil dataLen = 25 if longFrames { dataLen = 2 * protocol.MinStreamFrameSize } data = make([]byte, num*dataLen) for i := 0; i < num; i++ { for j := protocol.ByteCount(0); j < dataLen; j++ { data[protocol.ByteCount(i)*dataLen+j] = uint8(i) } } }) getRandomFrames := func() []frame { frames := make([]frame, num) for i := protocol.ByteCount(0); i < num; i++ { b := make([]byte, dataLen) Expect(copy(b, data[i*dataLen:])).To(BeEquivalentTo(dataLen)) frames[i] = frame{ offset: i * dataLen, data: b, } } rand.Shuffle(len(frames), func(i, j int) { frames[i], frames[j] = frames[j], frames[i] }) return frames } getData := func() []byte { var data []byte for { offset, b, cb := s.Pop() if b == nil { break } Expect(offset).To(BeEquivalentTo(len(data))) data = append(data, b...) if cb != nil { cb() } } return data } // push pushes data to the frame sorter // It creates a new callback and adds the push := func(data []byte, offset protocol.ByteCount) { cb, t := getCallback() ExpectWithOffset(1, s.Push(data, offset, cb)).To(Succeed()) callbacks = append(callbacks, t) } checkCallbacks := func() { ExpectWithOffset(1, callbacks).ToNot(BeEmpty()) for _, t := range callbacks { checkCallbackCalled(t) } } It("inserting frames in a random order", func() { frames := getRandomFrames() for _, f := range frames { push(f.data, f.offset) } checkGaps([]utils.ByteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}}) Expect(getData()).To(Equal(data)) Expect(s.queue).To(BeEmpty()) checkCallbacks() }) It("inserting frames in a random order, with some duplicates", func() { frames := getRandomFrames() for _, f := range frames { push(f.data, f.offset) if rand.Intn(10) < 5 { df := frames[rand.Intn(len(frames))] push(df.data, df.offset) } } checkGaps([]utils.ByteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}}) Expect(getData()).To(Equal(data)) Expect(s.queue).To(BeEmpty()) checkCallbacks() }) It("inserting frames in a random order, with randomly cut retransmissions", func() { frames := getRandomFrames() for _, f := range frames { push(f.data, f.offset) if rand.Intn(10) < 5 { length := protocol.ByteCount(1 + rand.Intn(int(4*dataLen))) if length >= num*dataLen { length = num*dataLen - 1 } b := make([]byte, length) offset := protocol.ByteCount(rand.Intn(int(num*dataLen - length))) Expect(copy(b, data[offset:offset+length])).To(BeEquivalentTo(length)) push(b, offset) } } checkGaps([]utils.ByteInterval{{Start: num * dataLen, End: protocol.MaxByteCount}}) Expect(getData()).To(Equal(data)) Expect(s.queue).To(BeEmpty()) checkCallbacks() }) }) } }) })