package quic import ( "encoding/binary" "time" "github.com/lucas-clemente/quic-go/internal/protocol" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("0-RTT queue", func() { var q *zeroRTTQueue queueDuration := scaleDuration(20 * time.Millisecond) BeforeEach(func() { q = newZeroRTTQueue() q.queueDuration = queueDuration }) AfterEach(func() { // dequeue all packets to make sure the timers are stopped q.mutex.Lock() for connID := range q.queue { for { q.mutex.Unlock() p := q.Dequeue(protocol.ConnectionID(connID)) q.mutex.Lock() if p != nil { break } } } q.mutex.Unlock() }) It("stores a 0-RTT packet", func() { connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} p := &receivedPacket{data: []byte("foobar")} q.Enqueue(connID, p) Expect(q.Dequeue(connID)).To(Equal(p)) Expect(q.Dequeue(connID)).To(BeNil()) }) It("returns a nil packet for unknown connection IDs", func() { Expect(q.Dequeue(protocol.ConnectionID{0x42})).To(BeNil()) }) It("only stores packets for Max0RTTQueues connection", func() { // fill up the queues for i := 0; i < protocol.Max0RTTQueues; i++ { data := make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(i)) q.Enqueue(protocol.ConnectionID(data), &receivedPacket{data: data}) } // now try to enqueue a packet for another connection ID connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} q.Enqueue(connID, &receivedPacket{data: []byte("foobar")}) Expect(q.Dequeue(connID)).To(BeNil()) // check that the other queues were all saved for i := 0; i < protocol.Max0RTTQueues; i++ { connID := make([]byte, 4) binary.BigEndian.PutUint32(connID, uint32(i)) p := q.Dequeue(connID) Expect(p).ToNot(BeNil()) Expect(binary.BigEndian.Uint32(p.data)).To(BeEquivalentTo(i)) } }) It("removes queues when packets are dequeued", func() { // fill up the queues for i := 0; i < protocol.Max0RTTQueues; i++ { data := make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(i)) q.Enqueue(protocol.ConnectionID(data), &receivedPacket{data: data}) } // now try to enqueue a packet for another connection ID connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} q.Enqueue(connID, &receivedPacket{data: []byte("foobar")}) Expect(q.Dequeue(connID)).To(BeNil()) // dequeue the packet from the first queue Expect(q.Dequeue(protocol.ConnectionID{0, 0, 0, 0})).ToNot(BeNil()) // now it should be possible to queue another packet q.Enqueue(connID, &receivedPacket{data: []byte("foobar")}) Expect(q.Dequeue(connID)).ToNot(BeNil()) }) It("limits the number of packets it stores for one connection", func() { connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} // fill up the queue for i := 0; i < protocol.Max0RTTQueueLen; i++ { data := make([]byte, 4) binary.BigEndian.PutUint32(data, uint32(i)) q.Enqueue(connID, &receivedPacket{data: data}) } // The queue is full now. This packet will be dropped. q.Enqueue(connID, &receivedPacket{data: []byte("foobar")}) for i := 0; i < protocol.Max0RTTQueueLen; i++ { p := q.Dequeue(connID) Expect(p).ToNot(BeNil()) Expect(binary.BigEndian.Uint32(p.data)).To(BeEquivalentTo(i)) } // The queue should now be empty. Expect(q.Dequeue(connID)).To(BeNil()) }) It("deletes packets if they aren't dequeued after a short while", func() { connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} p := &receivedPacket{data: []byte("foobar"), buffer: getPacketBuffer()} q.Enqueue(connID, p) time.Sleep(queueDuration * 3 / 2) Expect(q.Dequeue(connID)).To(BeNil()) }) })