github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/conn_id_manager_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"github.com/daeuniverse/quic-go/internal/protocol"
     5  	"github.com/daeuniverse/quic-go/internal/qerr"
     6  	"github.com/daeuniverse/quic-go/internal/wire"
     7  
     8  	. "github.com/onsi/ginkgo/v2"
     9  	. "github.com/onsi/gomega"
    10  )
    11  
    12  var _ = Describe("Connection ID Manager", func() {
    13  	var (
    14  		m             *connIDManager
    15  		frameQueue    []wire.Frame
    16  		tokenAdded    *protocol.StatelessResetToken
    17  		removedTokens []protocol.StatelessResetToken
    18  	)
    19  	initialConnID := protocol.ParseConnectionID([]byte{0, 0, 0, 0})
    20  
    21  	BeforeEach(func() {
    22  		frameQueue = nil
    23  		tokenAdded = nil
    24  		removedTokens = nil
    25  		m = newConnIDManager(
    26  			initialConnID,
    27  			func(token protocol.StatelessResetToken) { tokenAdded = &token },
    28  			func(token protocol.StatelessResetToken) { removedTokens = append(removedTokens, token) },
    29  			func(f wire.Frame,
    30  			) {
    31  				frameQueue = append(frameQueue, f)
    32  			})
    33  	})
    34  
    35  	get := func() (protocol.ConnectionID, protocol.StatelessResetToken) {
    36  		if m.queue.Len() == 0 {
    37  			return protocol.ConnectionID{}, protocol.StatelessResetToken{}
    38  		}
    39  		val := m.queue.Remove(m.queue.Front())
    40  		return val.ConnectionID, val.StatelessResetToken
    41  	}
    42  
    43  	It("returns the initial connection ID", func() {
    44  		Expect(m.Get()).To(Equal(initialConnID))
    45  	})
    46  
    47  	It("changes the initial connection ID", func() {
    48  		m.ChangeInitialConnID(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5}))
    49  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5})))
    50  	})
    51  
    52  	It("sets the token for the first connection ID", func() {
    53  		token := protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    54  		m.SetStatelessResetToken(token)
    55  		Expect(*m.activeStatelessResetToken).To(Equal(token))
    56  		Expect(*tokenAdded).To(Equal(token))
    57  	})
    58  
    59  	It("adds and gets connection IDs", func() {
    60  		Expect(m.Add(&wire.NewConnectionIDFrame{
    61  			SequenceNumber:      10,
    62  			ConnectionID:        protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
    63  			StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
    64  		})).To(Succeed())
    65  		Expect(m.Add(&wire.NewConnectionIDFrame{
    66  			SequenceNumber:      4,
    67  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
    68  			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
    69  		})).To(Succeed())
    70  		c1, rt1 := get()
    71  		Expect(c1).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
    72  		Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
    73  		c2, rt2 := get()
    74  		Expect(c2).To(Equal(protocol.ParseConnectionID([]byte{2, 3, 4, 5})))
    75  		Expect(rt2).To(Equal(protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}))
    76  		c3, _ := get()
    77  		Expect(c3).To(BeZero())
    78  	})
    79  
    80  	It("accepts duplicates", func() {
    81  		f1 := &wire.NewConnectionIDFrame{
    82  			SequenceNumber:      1,
    83  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
    84  			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
    85  		}
    86  		f2 := &wire.NewConnectionIDFrame{
    87  			SequenceNumber:      1,
    88  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
    89  			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
    90  		}
    91  		Expect(m.Add(f1)).To(Succeed())
    92  		Expect(m.Add(f2)).To(Succeed())
    93  		c1, rt1 := get()
    94  		Expect(c1).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
    95  		Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
    96  		c2, _ := get()
    97  		Expect(c2).To(BeZero())
    98  	})
    99  
   100  	It("ignores duplicates for the currently used connection ID", func() {
   101  		f := &wire.NewConnectionIDFrame{
   102  			SequenceNumber:      1,
   103  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   104  			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
   105  		}
   106  		m.SetHandshakeComplete()
   107  		Expect(m.Add(f)).To(Succeed())
   108  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
   109  		c, _ := get()
   110  		Expect(c).To(BeZero())
   111  		// Now send the same connection ID again. It should not be queued.
   112  		Expect(m.Add(f)).To(Succeed())
   113  		c, _ = get()
   114  		Expect(c).To(BeZero())
   115  	})
   116  
   117  	It("rejects duplicates with different connection IDs", func() {
   118  		Expect(m.Add(&wire.NewConnectionIDFrame{
   119  			SequenceNumber: 42,
   120  			ConnectionID:   protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   121  		})).To(Succeed())
   122  		Expect(m.Add(&wire.NewConnectionIDFrame{
   123  			SequenceNumber: 42,
   124  			ConnectionID:   protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
   125  		})).To(MatchError("received conflicting connection IDs for sequence number 42"))
   126  	})
   127  
   128  	It("rejects duplicates with different connection IDs", func() {
   129  		Expect(m.Add(&wire.NewConnectionIDFrame{
   130  			SequenceNumber:      42,
   131  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   132  			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
   133  		})).To(Succeed())
   134  		Expect(m.Add(&wire.NewConnectionIDFrame{
   135  			SequenceNumber:      42,
   136  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   137  			StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
   138  		})).To(MatchError("received conflicting stateless reset tokens for sequence number 42"))
   139  	})
   140  
   141  	It("retires connection IDs", func() {
   142  		Expect(m.Add(&wire.NewConnectionIDFrame{
   143  			SequenceNumber: 10,
   144  			ConnectionID:   protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   145  		})).To(Succeed())
   146  		Expect(m.Add(&wire.NewConnectionIDFrame{
   147  			SequenceNumber: 13,
   148  			ConnectionID:   protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
   149  		})).To(Succeed())
   150  		Expect(frameQueue).To(BeEmpty())
   151  		Expect(m.Add(&wire.NewConnectionIDFrame{
   152  			RetirePriorTo:  14,
   153  			SequenceNumber: 17,
   154  			ConnectionID:   protocol.ParseConnectionID([]byte{3, 4, 5, 6}),
   155  		})).To(Succeed())
   156  		Expect(frameQueue).To(HaveLen(3))
   157  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(10))
   158  		Expect(frameQueue[1].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(13))
   159  		Expect(frameQueue[2].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
   160  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{3, 4, 5, 6})))
   161  	})
   162  
   163  	It("ignores reordered connection IDs, if their sequence number was already retired", func() {
   164  		Expect(m.Add(&wire.NewConnectionIDFrame{
   165  			SequenceNumber: 10,
   166  			ConnectionID:   protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   167  			RetirePriorTo:  5,
   168  		})).To(Succeed())
   169  		Expect(frameQueue).To(HaveLen(1))
   170  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
   171  		frameQueue = nil
   172  		// If this NEW_CONNECTION_ID frame hadn't been reordered, we would have retired it before.
   173  		// Make sure it gets retired immediately now.
   174  		Expect(m.Add(&wire.NewConnectionIDFrame{
   175  			SequenceNumber: 4,
   176  			ConnectionID:   protocol.ParseConnectionID([]byte{4, 3, 2, 1}),
   177  		})).To(Succeed())
   178  		Expect(frameQueue).To(HaveLen(1))
   179  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(4))
   180  	})
   181  
   182  	It("ignores reordered connection IDs, if their sequence number was already retired or less than active", func() {
   183  		Expect(m.Add(&wire.NewConnectionIDFrame{
   184  			SequenceNumber: 10,
   185  			ConnectionID:   protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
   186  			RetirePriorTo:  5,
   187  		})).To(Succeed())
   188  		Expect(frameQueue).To(HaveLen(1))
   189  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
   190  		frameQueue = nil
   191  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})))
   192  
   193  		Expect(m.Add(&wire.NewConnectionIDFrame{
   194  			SequenceNumber: 9,
   195  			ConnectionID:   protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
   196  			RetirePriorTo:  5,
   197  		})).To(Succeed())
   198  		Expect(frameQueue).To(HaveLen(1))
   199  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(9))
   200  	})
   201  
   202  	It("accepts retransmissions for the connection ID that is in use", func() {
   203  		connID := protocol.ParseConnectionID([]byte{1, 2, 3, 4})
   204  
   205  		Expect(m.Add(&wire.NewConnectionIDFrame{
   206  			SequenceNumber: 1,
   207  			ConnectionID:   connID,
   208  		})).To(Succeed())
   209  		m.SetHandshakeComplete()
   210  		Expect(frameQueue).To(BeEmpty())
   211  		Expect(m.Get()).To(Equal(connID))
   212  		Expect(frameQueue).To(HaveLen(1))
   213  		Expect(frameQueue[0]).To(BeAssignableToTypeOf(&wire.RetireConnectionIDFrame{}))
   214  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
   215  		frameQueue = nil
   216  
   217  		Expect(m.Add(&wire.NewConnectionIDFrame{
   218  			SequenceNumber: 1,
   219  			ConnectionID:   connID,
   220  		})).To(Succeed())
   221  		Expect(frameQueue).To(BeEmpty())
   222  	})
   223  
   224  	It("errors when the peer sends too connection IDs", func() {
   225  		for i := uint8(1); i < protocol.MaxActiveConnectionIDs; i++ {
   226  			Expect(m.Add(&wire.NewConnectionIDFrame{
   227  				SequenceNumber:      uint64(i),
   228  				ConnectionID:        protocol.ParseConnectionID([]byte{i, i, i, i}),
   229  				StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
   230  			})).To(Succeed())
   231  		}
   232  		Expect(m.Add(&wire.NewConnectionIDFrame{
   233  			SequenceNumber:      uint64(9999),
   234  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   235  			StatelessResetToken: protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
   236  		})).To(MatchError(&qerr.TransportError{ErrorCode: qerr.ConnectionIDLimitError}))
   237  	})
   238  
   239  	It("initiates the first connection ID update as soon as possible", func() {
   240  		Expect(m.Get()).To(Equal(initialConnID))
   241  		m.SetHandshakeComplete()
   242  		Expect(m.Add(&wire.NewConnectionIDFrame{
   243  			SequenceNumber:      1,
   244  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   245  			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   246  		})).To(Succeed())
   247  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
   248  	})
   249  
   250  	It("waits until handshake completion before initiating a connection ID update", func() {
   251  		Expect(m.Get()).To(Equal(initialConnID))
   252  		Expect(m.Add(&wire.NewConnectionIDFrame{
   253  			SequenceNumber:      1,
   254  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   255  			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   256  		})).To(Succeed())
   257  		Expect(m.Get()).To(Equal(initialConnID))
   258  		m.SetHandshakeComplete()
   259  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
   260  	})
   261  
   262  	It("initiates subsequent updates when enough packets are sent", func() {
   263  		var s uint8
   264  		for s = uint8(1); s < protocol.MaxActiveConnectionIDs; s++ {
   265  			Expect(m.Add(&wire.NewConnectionIDFrame{
   266  				SequenceNumber:      uint64(s),
   267  				ConnectionID:        protocol.ParseConnectionID([]byte{s, s, s, s}),
   268  				StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
   269  			})).To(Succeed())
   270  		}
   271  
   272  		m.SetHandshakeComplete()
   273  		lastConnID := m.Get()
   274  		Expect(lastConnID).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
   275  
   276  		var counter int
   277  		for i := 0; i < 50*protocol.PacketsPerConnectionID; i++ {
   278  			m.SentPacket()
   279  
   280  			connID := m.Get()
   281  			if connID != lastConnID {
   282  				counter++
   283  				lastConnID = connID
   284  				Expect(removedTokens).To(HaveLen(1))
   285  				removedTokens = nil
   286  				Expect(m.Add(&wire.NewConnectionIDFrame{
   287  					SequenceNumber:      uint64(s),
   288  					ConnectionID:        protocol.ParseConnectionID([]byte{s, s, s, s}),
   289  					StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
   290  				})).To(Succeed())
   291  				s++
   292  			}
   293  		}
   294  		Expect(counter).To(BeNumerically("~", 50, 10))
   295  	})
   296  
   297  	It("retires delayed connection IDs that arrive after a higher connection ID was already retired", func() {
   298  		for s := uint8(10); s <= 10+protocol.MaxActiveConnectionIDs/2; s++ {
   299  			Expect(m.Add(&wire.NewConnectionIDFrame{
   300  				SequenceNumber:      uint64(s),
   301  				ConnectionID:        protocol.ParseConnectionID([]byte{s, s, s, s}),
   302  				StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
   303  			})).To(Succeed())
   304  		}
   305  		m.SetHandshakeComplete()
   306  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{10, 10, 10, 10})))
   307  		for {
   308  			m.SentPacket()
   309  			if m.Get() == protocol.ParseConnectionID([]byte{11, 11, 11, 11}) {
   310  				break
   311  			}
   312  		}
   313  		// The active conn ID is now {11, 11, 11, 11}
   314  		Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ParseConnectionID([]byte{12, 12, 12, 12})))
   315  		// Add a delayed connection ID. It should just be ignored now.
   316  		frameQueue = nil
   317  		Expect(m.Add(&wire.NewConnectionIDFrame{
   318  			SequenceNumber:      uint64(5),
   319  			ConnectionID:        protocol.ParseConnectionID([]byte{5, 5, 5, 5}),
   320  			StatelessResetToken: protocol.StatelessResetToken{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
   321  		})).To(Succeed())
   322  		Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ParseConnectionID([]byte{12, 12, 12, 12})))
   323  		Expect(frameQueue).To(HaveLen(1))
   324  		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(5))
   325  	})
   326  
   327  	It("only initiates subsequent updates when enough if enough connection IDs are queued", func() {
   328  		for i := uint8(1); i <= protocol.MaxActiveConnectionIDs/2; i++ {
   329  			Expect(m.Add(&wire.NewConnectionIDFrame{
   330  				SequenceNumber:      uint64(i),
   331  				ConnectionID:        protocol.ParseConnectionID([]byte{i, i, i, i}),
   332  				StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
   333  			})).To(Succeed())
   334  		}
   335  		m.SetHandshakeComplete()
   336  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
   337  		for i := 0; i < 2*protocol.PacketsPerConnectionID; i++ {
   338  			m.SentPacket()
   339  		}
   340  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
   341  		Expect(m.Add(&wire.NewConnectionIDFrame{
   342  			SequenceNumber: 1337,
   343  			ConnectionID:   protocol.ParseConnectionID([]byte{1, 3, 3, 7}),
   344  		})).To(Succeed())
   345  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{2, 2, 2, 2})))
   346  		Expect(removedTokens).To(HaveLen(1))
   347  		Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}))
   348  	})
   349  
   350  	It("removes the currently active stateless reset token when it is closed", func() {
   351  		m.Close()
   352  		Expect(removedTokens).To(BeEmpty())
   353  		Expect(m.Add(&wire.NewConnectionIDFrame{
   354  			SequenceNumber:      1,
   355  			ConnectionID:        protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
   356  			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
   357  		})).To(Succeed())
   358  		m.SetHandshakeComplete()
   359  		Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
   360  		m.Close()
   361  		Expect(removedTokens).To(HaveLen(1))
   362  		Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}))
   363  	})
   364  })