diff --git a/internal/quic/cmd/interop/main.go b/internal/quic/cmd/interop/main.go index 2ca5d652a..20f737b52 100644 --- a/internal/quic/cmd/interop/main.go +++ b/internal/quic/cmd/interop/main.go @@ -157,7 +157,7 @@ func basicTest(ctx context.Context, config *quic.Config, urls []string) { } } -func serve(ctx context.Context, l *quic.Listener) error { +func serve(ctx context.Context, l *quic.Endpoint) error { for { c, err := l.Accept(ctx) if err != nil { @@ -221,7 +221,7 @@ func parseURL(s string) (u *url.URL, authority string, err error) { return u, authority, nil } -func fetchFrom(ctx context.Context, l *quic.Listener, addr string, urls []*url.URL) { +func fetchFrom(ctx context.Context, l *quic.Endpoint, addr string, urls []*url.URL) { conn, err := l.Dial(ctx, "udp", addr) if err != nil { log.Printf("%v: %v", addr, err) diff --git a/internal/quic/conn.go b/internal/quic/conn.go index ff96ff760..31e789b1d 100644 --- a/internal/quic/conn.go +++ b/internal/quic/conn.go @@ -21,7 +21,7 @@ import ( // Multiple goroutines may invoke methods on a Conn simultaneously. type Conn struct { side connSide - listener *Listener + endpoint *Endpoint config *Config testHooks connTestHooks peerAddr netip.AddrPort @@ -92,10 +92,10 @@ type newServerConnIDs struct { retrySrcConnID []byte // source from server's Retry } -func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip.AddrPort, config *Config, l *Listener) (conn *Conn, _ error) { +func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip.AddrPort, config *Config, e *Endpoint) (conn *Conn, _ error) { c := &Conn{ side: side, - listener: l, + endpoint: e, config: config, peerAddr: peerAddr, msgc: make(chan any, 1), @@ -115,8 +115,8 @@ func newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip // non-blocking operation. c.msgc = make(chan any, 1) - if l.testHooks != nil { - l.testHooks.newConn(c) + if e.testHooks != nil { + e.testHooks.newConn(c) } // initialConnID is the connection ID used to generate Initial packet protection keys. @@ -187,7 +187,7 @@ func (c *Conn) confirmHandshake(now time.Time) { if c.side == serverSide { // When the server confirms the handshake, it sends a HANDSHAKE_DONE. c.handshakeConfirmed.setUnsent() - c.listener.serverConnEstablished(c) + c.endpoint.serverConnEstablished(c) } else { // The client never sends a HANDSHAKE_DONE, so we set handshakeConfirmed // to the received state, indicating that the handshake is confirmed and we @@ -265,7 +265,7 @@ var errIdleTimeout = errors.New("idle timeout") func (c *Conn) loop(now time.Time) { defer close(c.donec) defer c.tls.Close() - defer c.listener.connDrained(c) + defer c.endpoint.connDrained(c) defer c.logConnectionClosed() // The connection timer sends a message to the connection loop on expiry. diff --git a/internal/quic/conn_close_test.go b/internal/quic/conn_close_test.go index 0dd46dd20..49881e62f 100644 --- a/internal/quic/conn_close_test.go +++ b/internal/quic/conn_close_test.go @@ -205,13 +205,13 @@ func TestConnCloseReceiveInHandshake(t *testing.T) { tc.wantIdle("no more frames to send") } -func TestConnCloseClosedByListener(t *testing.T) { +func TestConnCloseClosedByEndpoint(t *testing.T) { ctx := canceledContext() tc := newTestConn(t, clientSide) tc.handshake() - tc.listener.l.Close(ctx) - tc.wantFrame("listener closes connection before exiting", + tc.endpoint.e.Close(ctx) + tc.wantFrame("endpoint closes connection before exiting", packetType1RTT, debugFrameConnectionCloseTransport{ code: errNo, }) diff --git a/internal/quic/conn_id.go b/internal/quic/conn_id.go index 439c22123..2efe8d6b5 100644 --- a/internal/quic/conn_id.go +++ b/internal/quic/conn_id.go @@ -76,7 +76,7 @@ func (s *connIDState) initClient(c *Conn) error { cid: locid, }) s.nextLocalSeq = 1 - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.addConnID(c, locid) }) @@ -117,7 +117,7 @@ func (s *connIDState) initServer(c *Conn, cids newServerConnIDs) error { cid: locid, }) s.nextLocalSeq = 1 - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.addConnID(c, dstConnID) conns.addConnID(c, locid) }) @@ -194,7 +194,7 @@ func (s *connIDState) issueLocalIDs(c *Conn) error { s.needSend = true toIssue-- } - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { for _, cid := range newIDs { conns.addConnID(c, cid) } @@ -247,7 +247,7 @@ func (s *connIDState) validateTransportParameters(c *Conn, isRetry bool, p trans } token := statelessResetToken(p.statelessResetToken) s.remote[0].resetToken = token - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.addResetToken(c, token) }) } @@ -276,7 +276,7 @@ func (s *connIDState) handlePacket(c *Conn, ptype packetType, srcConnID []byte) // the client. Discard the transient, client-chosen connection ID used // for Initial packets; the client will never send it again. cid := s.local[0].cid - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.retireConnID(c, cid) }) s.local = append(s.local[:0], s.local[1:]...) @@ -314,7 +314,7 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re rcid := &s.remote[i] if !rcid.retired && rcid.seq >= 0 && rcid.seq < s.retireRemotePriorTo { s.retireRemote(rcid) - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.retireResetToken(c, rcid.resetToken) }) } @@ -350,7 +350,7 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re s.retireRemote(&s.remote[len(s.remote)-1]) } else { active++ - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.addResetToken(c, resetToken) }) } @@ -399,7 +399,7 @@ func (s *connIDState) handleRetireConnID(c *Conn, seq int64) error { for i := range s.local { if s.local[i].seq == seq { cid := s.local[i].cid - c.listener.connsMap.updateConnIDs(func(conns *connsMap) { + c.endpoint.connsMap.updateConnIDs(func(conns *connsMap) { conns.retireConnID(c, cid) }) s.local = append(s.local[:i], s.local[i+1:]...) @@ -463,7 +463,7 @@ func (s *connIDState) appendFrames(c *Conn, pnum packetNumber, pto bool) bool { s.local[i].seq, retireBefore, s.local[i].cid, - c.listener.resetGen.tokenForConnID(s.local[i].cid), + c.endpoint.resetGen.tokenForConnID(s.local[i].cid), ) { return false } diff --git a/internal/quic/conn_id_test.go b/internal/quic/conn_id_test.go index 314a6b384..d44472e81 100644 --- a/internal/quic/conn_id_test.go +++ b/internal/quic/conn_id_test.go @@ -651,16 +651,16 @@ func TestConnIDsCleanedUpAfterClose(t *testing.T) { // Wait for the conn to drain. // Then wait for the conn loop to exit, // and force an immediate sync of the connsMap updates - // (normally only done by the listener read loop). + // (normally only done by the endpoint read loop). tc.advanceToTimer() <-tc.conn.donec - tc.listener.l.connsMap.applyUpdates() + tc.endpoint.e.connsMap.applyUpdates() - if got := len(tc.listener.l.connsMap.byConnID); got != 0 { - t.Errorf("%v conn ids in listener map after closing, want 0", got) + if got := len(tc.endpoint.e.connsMap.byConnID); got != 0 { + t.Errorf("%v conn ids in endpoint map after closing, want 0", got) } - if got := len(tc.listener.l.connsMap.byResetToken); got != 0 { - t.Errorf("%v reset tokens in listener map after closing, want 0", got) + if got := len(tc.endpoint.e.connsMap.byResetToken); got != 0 { + t.Errorf("%v reset tokens in endpoint map after closing, want 0", got) } }) } diff --git a/internal/quic/conn_send.go b/internal/quic/conn_send.go index e45dc8af3..4065474d2 100644 --- a/internal/quic/conn_send.go +++ b/internal/quic/conn_send.go @@ -170,7 +170,7 @@ func (c *Conn) maybeSend(now time.Time) (next time.Time) { } } - c.listener.sendDatagram(buf, c.peerAddr) + c.endpoint.sendDatagram(buf, c.peerAddr) } } diff --git a/internal/quic/conn_test.go b/internal/quic/conn_test.go index 70ba7b392..c57ba1487 100644 --- a/internal/quic/conn_test.go +++ b/internal/quic/conn_test.go @@ -34,12 +34,12 @@ func TestConnTestConn(t *testing.T) { tc.conn.runOnLoop(func(now time.Time, c *Conn) { ranAt = now }) - if !ranAt.Equal(tc.listener.now) { - t.Errorf("func ran on loop at %v, want %v", ranAt, tc.listener.now) + if !ranAt.Equal(tc.endpoint.now) { + t.Errorf("func ran on loop at %v, want %v", ranAt, tc.endpoint.now) } tc.wait() - nextTime := tc.listener.now.Add(defaultMaxIdleTimeout / 2) + nextTime := tc.endpoint.now.Add(defaultMaxIdleTimeout / 2) tc.advanceTo(nextTime) tc.conn.runOnLoop(func(now time.Time, c *Conn) { ranAt = now @@ -117,7 +117,7 @@ const maxTestKeyPhases = 3 type testConn struct { t *testing.T conn *Conn - listener *testListener + endpoint *testEndpoint timer time.Time timerLastFired time.Time idlec chan struct{} // only accessed on the conn's loop @@ -220,27 +220,27 @@ func newTestConn(t *testing.T, side connSide, opts ...any) *testConn { } } - listener := newTestListener(t, config) - listener.configTransportParams = configTransportParams - listener.configTestConn = configTestConn - conn, err := listener.l.newConn( - listener.now, + endpoint := newTestEndpoint(t, config) + endpoint.configTransportParams = configTransportParams + endpoint.configTestConn = configTestConn + conn, err := endpoint.e.newConn( + endpoint.now, side, cids, netip.MustParseAddrPort("127.0.0.1:443")) if err != nil { t.Fatal(err) } - tc := listener.conns[conn] + tc := endpoint.conns[conn] tc.wait() return tc } -func newTestConnForConn(t *testing.T, listener *testListener, conn *Conn) *testConn { +func newTestConnForConn(t *testing.T, endpoint *testEndpoint, conn *Conn) *testConn { t.Helper() tc := &testConn{ t: t, - listener: listener, + endpoint: endpoint, conn: conn, peerConnID: testPeerConnID(0), ignoreFrames: map[byte]bool{ @@ -251,14 +251,14 @@ func newTestConnForConn(t *testing.T, listener *testListener, conn *Conn) *testC recvDatagram: make(chan *datagram), } t.Cleanup(tc.cleanup) - for _, f := range listener.configTestConn { + for _, f := range endpoint.configTestConn { f(tc) } conn.testHooks = (*testConnHooks)(tc) - if listener.peerTLSConn != nil { - tc.peerTLSConn = listener.peerTLSConn - listener.peerTLSConn = nil + if endpoint.peerTLSConn != nil { + tc.peerTLSConn = endpoint.peerTLSConn + endpoint.peerTLSConn = nil return tc } @@ -267,7 +267,7 @@ func newTestConnForConn(t *testing.T, listener *testListener, conn *Conn) *testC if conn.side == clientSide { peerProvidedParams.originalDstConnID = testLocalConnID(-1) } - for _, f := range listener.configTransportParams { + for _, f := range endpoint.configTransportParams { f(&peerProvidedParams) } @@ -286,13 +286,13 @@ func newTestConnForConn(t *testing.T, listener *testListener, conn *Conn) *testC // advance causes time to pass. func (tc *testConn) advance(d time.Duration) { tc.t.Helper() - tc.listener.advance(d) + tc.endpoint.advance(d) } // advanceTo sets the current time. func (tc *testConn) advanceTo(now time.Time) { tc.t.Helper() - tc.listener.advanceTo(now) + tc.endpoint.advanceTo(now) } // advanceToTimer sets the current time to the time of the Conn's next timer event. @@ -307,10 +307,10 @@ func (tc *testConn) timerDelay() time.Duration { if tc.timer.IsZero() { return math.MaxInt64 // infinite } - if tc.timer.Before(tc.listener.now) { + if tc.timer.Before(tc.endpoint.now) { return 0 } - return tc.timer.Sub(tc.listener.now) + return tc.timer.Sub(tc.endpoint.now) } const infiniteDuration = time.Duration(math.MaxInt64) @@ -320,10 +320,10 @@ func (tc *testConn) timeUntilEvent() time.Duration { if tc.timer.IsZero() { return infiniteDuration } - if tc.timer.Before(tc.listener.now) { + if tc.timer.Before(tc.endpoint.now) { return 0 } - return tc.timer.Sub(tc.listener.now) + return tc.timer.Sub(tc.endpoint.now) } // wait blocks until the conn becomes idle. @@ -400,7 +400,7 @@ func logDatagram(t *testing.T, text string, d *testDatagram) { // write sends the Conn a datagram. func (tc *testConn) write(d *testDatagram) { tc.t.Helper() - tc.listener.writeDatagram(d) + tc.endpoint.writeDatagram(d) } // writeFrame sends the Conn a datagram containing the given frames. @@ -466,11 +466,11 @@ func (tc *testConn) readDatagram() *testDatagram { tc.wait() tc.sentPackets = nil tc.sentFrames = nil - buf := tc.listener.read() + buf := tc.endpoint.read() if buf == nil { return nil } - d := parseTestDatagram(tc.t, tc.listener, tc, buf) + d := parseTestDatagram(tc.t, tc.endpoint, tc, buf) // Log the datagram before removing ignored frames. // When things go wrong, it's useful to see all the frames. logDatagram(tc.t, "-> conn under test sends", d) @@ -771,7 +771,7 @@ func encodeTestPacket(t *testing.T, tc *testConn, p *testPacket, pad int) []byte return w.datagram() } -func parseTestDatagram(t *testing.T, tl *testListener, tc *testConn, buf []byte) *testDatagram { +func parseTestDatagram(t *testing.T, te *testEndpoint, tc *testConn, buf []byte) *testDatagram { t.Helper() bufSize := len(buf) d := &testDatagram{} @@ -784,7 +784,7 @@ func parseTestDatagram(t *testing.T, tl *testListener, tc *testConn, buf []byte) ptype := getPacketType(buf) switch ptype { case packetTypeRetry: - retry, ok := parseRetryPacket(buf, tl.lastInitialDstConnID) + retry, ok := parseRetryPacket(buf, te.lastInitialDstConnID) if !ok { t.Fatalf("could not parse %v packet", ptype) } @@ -938,7 +938,7 @@ func (tc *testConnHooks) init() { tc.keysInitial.r = tc.conn.keysInitial.w tc.keysInitial.w = tc.conn.keysInitial.r if tc.conn.side == serverSide { - tc.listener.acceptQueue = append(tc.listener.acceptQueue, (*testConn)(tc)) + tc.endpoint.acceptQueue = append(tc.endpoint.acceptQueue, (*testConn)(tc)) } } @@ -1039,20 +1039,20 @@ func (tc *testConnHooks) handleTLSEvent(e tls.QUICEvent) { func (tc *testConnHooks) nextMessage(msgc chan any, timer time.Time) (now time.Time, m any) { tc.timer = timer for { - if !timer.IsZero() && !timer.After(tc.listener.now) { + if !timer.IsZero() && !timer.After(tc.endpoint.now) { if timer.Equal(tc.timerLastFired) { // If the connection timer fires at time T, the Conn should take some // action to advance the timer into the future. If the Conn reschedules // the timer for the same time, it isn't making progress and we have a bug. - tc.t.Errorf("connection timer spinning; now=%v timer=%v", tc.listener.now, timer) + tc.t.Errorf("connection timer spinning; now=%v timer=%v", tc.endpoint.now, timer) } else { tc.timerLastFired = timer - return tc.listener.now, timerEvent{} + return tc.endpoint.now, timerEvent{} } } select { case m := <-msgc: - return tc.listener.now, m + return tc.endpoint.now, m default: } if !tc.wakeAsync() { @@ -1066,7 +1066,7 @@ func (tc *testConnHooks) nextMessage(msgc chan any, timer time.Time) (now time.T close(idlec) } m = <-msgc - return tc.listener.now, m + return tc.endpoint.now, m } func (tc *testConnHooks) newConnID(seq int64) ([]byte, error) { @@ -1074,7 +1074,7 @@ func (tc *testConnHooks) newConnID(seq int64) ([]byte, error) { } func (tc *testConnHooks) timeNow() time.Time { - return tc.listener.now + return tc.endpoint.now } // testLocalConnID returns the connection ID with a given sequence number diff --git a/internal/quic/listener.go b/internal/quic/listener.go index ca8f9b25a..82a08a18c 100644 --- a/internal/quic/listener.go +++ b/internal/quic/listener.go @@ -17,14 +17,14 @@ import ( "time" ) -// A Listener listens for QUIC traffic on a network address. +// An Endpoint handles QUIC traffic on a network address. // It can accept inbound connections or create outbound ones. // -// Multiple goroutines may invoke methods on a Listener simultaneously. -type Listener struct { +// Multiple goroutines may invoke methods on an Endpoint simultaneously. +type Endpoint struct { config *Config udpConn udpConn - testHooks listenerTestHooks + testHooks endpointTestHooks resetGen statelessResetTokenGenerator retry retryState @@ -37,7 +37,7 @@ type Listener struct { closec chan struct{} // closed when the listen loop exits } -type listenerTestHooks interface { +type endpointTestHooks interface { timeNow() time.Time newConn(c *Conn) } @@ -53,7 +53,7 @@ type udpConn interface { // Listen listens on a local network address. // The configuration config must be non-nil. -func Listen(network, address string, config *Config) (*Listener, error) { +func Listen(network, address string, config *Config) (*Endpoint, error) { if config.TLSConfig == nil { return nil, errors.New("TLSConfig is not set") } @@ -65,11 +65,11 @@ func Listen(network, address string, config *Config) (*Listener, error) { if err != nil { return nil, err } - return newListener(udpConn, config, nil) + return newEndpoint(udpConn, config, nil) } -func newListener(udpConn udpConn, config *Config, hooks listenerTestHooks) (*Listener, error) { - l := &Listener{ +func newEndpoint(udpConn udpConn, config *Config, hooks endpointTestHooks) (*Endpoint, error) { + e := &Endpoint{ config: config, udpConn: udpConn, testHooks: hooks, @@ -77,70 +77,70 @@ func newListener(udpConn udpConn, config *Config, hooks listenerTestHooks) (*Lis acceptQueue: newQueue[*Conn](), closec: make(chan struct{}), } - l.resetGen.init(config.StatelessResetKey) - l.connsMap.init() + e.resetGen.init(config.StatelessResetKey) + e.connsMap.init() if config.RequireAddressValidation { - if err := l.retry.init(); err != nil { + if err := e.retry.init(); err != nil { return nil, err } } - go l.listen() - return l, nil + go e.listen() + return e, nil } // LocalAddr returns the local network address. -func (l *Listener) LocalAddr() netip.AddrPort { - a, _ := l.udpConn.LocalAddr().(*net.UDPAddr) +func (e *Endpoint) LocalAddr() netip.AddrPort { + a, _ := e.udpConn.LocalAddr().(*net.UDPAddr) return a.AddrPort() } -// Close closes the listener. -// Any blocked operations on the Listener or associated Conns and Stream will be unblocked +// Close closes the Endpoint. +// Any blocked operations on the Endpoint or associated Conns and Stream will be unblocked // and return errors. // // Close aborts every open connection. // Data in stream read and write buffers is discarded. // It waits for the peers of any open connection to acknowledge the connection has been closed. -func (l *Listener) Close(ctx context.Context) error { - l.acceptQueue.close(errors.New("listener closed")) - l.connsMu.Lock() - if !l.closing { - l.closing = true - for c := range l.conns { +func (e *Endpoint) Close(ctx context.Context) error { + e.acceptQueue.close(errors.New("endpoint closed")) + e.connsMu.Lock() + if !e.closing { + e.closing = true + for c := range e.conns { c.Abort(localTransportError{code: errNo}) } - if len(l.conns) == 0 { - l.udpConn.Close() + if len(e.conns) == 0 { + e.udpConn.Close() } } - l.connsMu.Unlock() + e.connsMu.Unlock() select { - case <-l.closec: + case <-e.closec: case <-ctx.Done(): - l.connsMu.Lock() - for c := range l.conns { + e.connsMu.Lock() + for c := range e.conns { c.exit() } - l.connsMu.Unlock() + e.connsMu.Unlock() return ctx.Err() } return nil } -// Accept waits for and returns the next connection to the listener. -func (l *Listener) Accept(ctx context.Context) (*Conn, error) { - return l.acceptQueue.get(ctx, nil) +// Accept waits for and returns the next connection. +func (e *Endpoint) Accept(ctx context.Context) (*Conn, error) { + return e.acceptQueue.get(ctx, nil) } // Dial creates and returns a connection to a network address. -func (l *Listener) Dial(ctx context.Context, network, address string) (*Conn, error) { +func (e *Endpoint) Dial(ctx context.Context, network, address string) (*Conn, error) { u, err := net.ResolveUDPAddr(network, address) if err != nil { return nil, err } addr := u.AddrPort() addr = netip.AddrPortFrom(addr.Addr().Unmap(), addr.Port()) - c, err := l.newConn(time.Now(), clientSide, newServerConnIDs{}, addr) + c, err := e.newConn(time.Now(), clientSide, newServerConnIDs{}, addr) if err != nil { return nil, err } @@ -151,29 +151,29 @@ func (l *Listener) Dial(ctx context.Context, network, address string) (*Conn, er return c, nil } -func (l *Listener) newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip.AddrPort) (*Conn, error) { - l.connsMu.Lock() - defer l.connsMu.Unlock() - if l.closing { - return nil, errors.New("listener closed") +func (e *Endpoint) newConn(now time.Time, side connSide, cids newServerConnIDs, peerAddr netip.AddrPort) (*Conn, error) { + e.connsMu.Lock() + defer e.connsMu.Unlock() + if e.closing { + return nil, errors.New("endpoint closed") } - c, err := newConn(now, side, cids, peerAddr, l.config, l) + c, err := newConn(now, side, cids, peerAddr, e.config, e) if err != nil { return nil, err } - l.conns[c] = struct{}{} + e.conns[c] = struct{}{} return c, nil } // serverConnEstablished is called by a conn when the handshake completes // for an inbound (serverSide) connection. -func (l *Listener) serverConnEstablished(c *Conn) { - l.acceptQueue.put(c) +func (e *Endpoint) serverConnEstablished(c *Conn) { + e.acceptQueue.put(c) } // connDrained is called by a conn when it leaves the draining state, // either when the peer acknowledges connection closure or the drain timeout expires. -func (l *Listener) connDrained(c *Conn) { +func (e *Endpoint) connDrained(c *Conn) { var cids [][]byte for i := range c.connIDState.local { cids = append(cids, c.connIDState.local[i].cid) @@ -182,7 +182,7 @@ func (l *Listener) connDrained(c *Conn) { for i := range c.connIDState.remote { tokens = append(tokens, c.connIDState.remote[i].resetToken) } - l.connsMap.updateConnIDs(func(conns *connsMap) { + e.connsMap.updateConnIDs(func(conns *connsMap) { for _, cid := range cids { conns.retireConnID(c, cid) } @@ -190,60 +190,60 @@ func (l *Listener) connDrained(c *Conn) { conns.retireResetToken(c, token) } }) - l.connsMu.Lock() - defer l.connsMu.Unlock() - delete(l.conns, c) - if l.closing && len(l.conns) == 0 { - l.udpConn.Close() + e.connsMu.Lock() + defer e.connsMu.Unlock() + delete(e.conns, c) + if e.closing && len(e.conns) == 0 { + e.udpConn.Close() } } -func (l *Listener) listen() { - defer close(l.closec) +func (e *Endpoint) listen() { + defer close(e.closec) for { m := newDatagram() // TODO: Read and process the ECN (explicit congestion notification) field. // https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-13.4 - n, _, _, addr, err := l.udpConn.ReadMsgUDPAddrPort(m.b, nil) + n, _, _, addr, err := e.udpConn.ReadMsgUDPAddrPort(m.b, nil) if err != nil { - // The user has probably closed the listener. + // The user has probably closed the endpoint. // We currently don't surface errors from other causes; - // we could check to see if the listener has been closed and + // we could check to see if the endpoint has been closed and // record the unexpected error if it has not. return } if n == 0 { continue } - if l.connsMap.updateNeeded.Load() { - l.connsMap.applyUpdates() + if e.connsMap.updateNeeded.Load() { + e.connsMap.applyUpdates() } m.addr = addr m.b = m.b[:n] - l.handleDatagram(m) + e.handleDatagram(m) } } -func (l *Listener) handleDatagram(m *datagram) { +func (e *Endpoint) handleDatagram(m *datagram) { dstConnID, ok := dstConnIDForDatagram(m.b) if !ok { m.recycle() return } - c := l.connsMap.byConnID[string(dstConnID)] + c := e.connsMap.byConnID[string(dstConnID)] if c == nil { // TODO: Move this branch into a separate goroutine to avoid blocking - // the listener while processing packets. - l.handleUnknownDestinationDatagram(m) + // the endpoint while processing packets. + e.handleUnknownDestinationDatagram(m) return } - // TODO: This can block the listener while waiting for the conn to accept the dgram. + // TODO: This can block the endpoint while waiting for the conn to accept the dgram. // Think about buffering between the receive loop and the conn. c.sendMsg(m) } -func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { +func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) { defer func() { if m != nil { m.recycle() @@ -254,15 +254,15 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { return } var now time.Time - if l.testHooks != nil { - now = l.testHooks.timeNow() + if e.testHooks != nil { + now = e.testHooks.timeNow() } else { now = time.Now() } // Check to see if this is a stateless reset. var token statelessResetToken copy(token[:], m.b[len(m.b)-len(token):]) - if c := l.connsMap.byResetToken[token]; c != nil { + if c := e.connsMap.byResetToken[token]; c != nil { c.sendMsg(func(now time.Time, c *Conn) { c.handleStatelessReset(now, token) }) @@ -271,7 +271,7 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { // If this is a 1-RTT packet, there's nothing productive we can do with it. // Send a stateless reset if possible. if !isLongHeader(m.b[0]) { - l.maybeSendStatelessReset(m.b, m.addr) + e.maybeSendStatelessReset(m.b, m.addr) return } p, ok := parseGenericLongHeaderPacket(m.b) @@ -285,7 +285,7 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { return default: // Unknown version. - l.sendVersionNegotiation(p, m.addr) + e.sendVersionNegotiation(p, m.addr) return } if getPacketType(m.b) != packetTypeInitial { @@ -300,10 +300,10 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { srcConnID: p.srcConnID, dstConnID: p.dstConnID, } - if l.config.RequireAddressValidation { + if e.config.RequireAddressValidation { var ok bool cids.retrySrcConnID = p.dstConnID - cids.originalDstConnID, ok = l.validateInitialAddress(now, p, m.addr) + cids.originalDstConnID, ok = e.validateInitialAddress(now, p, m.addr) if !ok { return } @@ -311,7 +311,7 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { cids.originalDstConnID = p.dstConnID } var err error - c, err := l.newConn(now, serverSide, cids, m.addr) + c, err := e.newConn(now, serverSide, cids, m.addr) if err != nil { // The accept queue is probably full. // We could send a CONNECTION_CLOSE to the peer to reject the connection. @@ -323,8 +323,8 @@ func (l *Listener) handleUnknownDestinationDatagram(m *datagram) { m = nil // don't recycle, sendMsg takes ownership } -func (l *Listener) maybeSendStatelessReset(b []byte, addr netip.AddrPort) { - if !l.resetGen.canReset { +func (e *Endpoint) maybeSendStatelessReset(b []byte, addr netip.AddrPort) { + if !e.resetGen.canReset { // Config.StatelessResetKey isn't set, so we don't send stateless resets. return } @@ -339,7 +339,7 @@ func (l *Listener) maybeSendStatelessReset(b []byte, addr netip.AddrPort) { } // TODO: Rate limit stateless resets. cid := b[1:][:connIDLen] - token := l.resetGen.tokenForConnID(cid) + token := e.resetGen.tokenForConnID(cid) // We want to generate a stateless reset that is as short as possible, // but long enough to be difficult to distinguish from a 1-RTT packet. // @@ -364,17 +364,17 @@ func (l *Listener) maybeSendStatelessReset(b []byte, addr netip.AddrPort) { b[0] &^= headerFormLong // clear long header bit b[0] |= fixedBit // set fixed bit copy(b[len(b)-statelessResetTokenLen:], token[:]) - l.sendDatagram(b, addr) + e.sendDatagram(b, addr) } -func (l *Listener) sendVersionNegotiation(p genericLongPacket, addr netip.AddrPort) { +func (e *Endpoint) sendVersionNegotiation(p genericLongPacket, addr netip.AddrPort) { m := newDatagram() m.b = appendVersionNegotiation(m.b[:0], p.srcConnID, p.dstConnID, quicVersion1) - l.sendDatagram(m.b, addr) + e.sendDatagram(m.b, addr) m.recycle() } -func (l *Listener) sendConnectionClose(in genericLongPacket, addr netip.AddrPort, code transportError) { +func (e *Endpoint) sendConnectionClose(in genericLongPacket, addr netip.AddrPort, code transportError) { keys := initialKeys(in.dstConnID, serverSide) var w packetWriter p := longPacket{ @@ -393,15 +393,15 @@ func (l *Listener) sendConnectionClose(in genericLongPacket, addr netip.AddrPort if len(buf) == 0 { return } - l.sendDatagram(buf, addr) + e.sendDatagram(buf, addr) } -func (l *Listener) sendDatagram(p []byte, addr netip.AddrPort) error { - _, err := l.udpConn.WriteToUDPAddrPort(p, addr) +func (e *Endpoint) sendDatagram(p []byte, addr netip.AddrPort) error { + _, err := e.udpConn.WriteToUDPAddrPort(p, addr) return err } -// A connsMap is a listener's mapping of conn ids and reset tokens to conns. +// A connsMap is an endpoint's mapping of conn ids and reset tokens to conns. type connsMap struct { byConnID map[string]*Conn byResetToken map[statelessResetToken]*Conn diff --git a/internal/quic/listener_test.go b/internal/quic/listener_test.go index 037fb21b4..f9fc80152 100644 --- a/internal/quic/listener_test.go +++ b/internal/quic/listener_test.go @@ -64,39 +64,39 @@ func TestStreamTransfer(t *testing.T) { func newLocalConnPair(t *testing.T, conf1, conf2 *Config) (clientConn, serverConn *Conn) { t.Helper() ctx := context.Background() - l1 := newLocalListener(t, serverSide, conf1) - l2 := newLocalListener(t, clientSide, conf2) - c2, err := l2.Dial(ctx, "udp", l1.LocalAddr().String()) + e1 := newLocalEndpoint(t, serverSide, conf1) + e2 := newLocalEndpoint(t, clientSide, conf2) + c2, err := e2.Dial(ctx, "udp", e1.LocalAddr().String()) if err != nil { t.Fatal(err) } - c1, err := l1.Accept(ctx) + c1, err := e1.Accept(ctx) if err != nil { t.Fatal(err) } return c2, c1 } -func newLocalListener(t *testing.T, side connSide, conf *Config) *Listener { +func newLocalEndpoint(t *testing.T, side connSide, conf *Config) *Endpoint { t.Helper() if conf.TLSConfig == nil { newConf := *conf conf = &newConf conf.TLSConfig = newTestTLSConfig(side) } - l, err := Listen("udp", "127.0.0.1:0", conf) + e, err := Listen("udp", "127.0.0.1:0", conf) if err != nil { t.Fatal(err) } t.Cleanup(func() { - l.Close(context.Background()) + e.Close(context.Background()) }) - return l + return e } -type testListener struct { +type testEndpoint struct { t *testing.T - l *Listener + e *Endpoint now time.Time recvc chan *datagram idlec chan struct{} @@ -109,8 +109,8 @@ type testListener struct { lastInitialDstConnID []byte // for parsing Retry packets } -func newTestListener(t *testing.T, config *Config) *testListener { - tl := &testListener{ +func newTestEndpoint(t *testing.T, config *Config) *testEndpoint { + te := &testEndpoint{ t: t, now: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), recvc: make(chan *datagram), @@ -118,52 +118,52 @@ func newTestListener(t *testing.T, config *Config) *testListener { conns: make(map[*Conn]*testConn), } var err error - tl.l, err = newListener((*testListenerUDPConn)(tl), config, (*testListenerHooks)(tl)) + te.e, err = newEndpoint((*testEndpointUDPConn)(te), config, (*testEndpointHooks)(te)) if err != nil { t.Fatal(err) } - t.Cleanup(tl.cleanup) - return tl + t.Cleanup(te.cleanup) + return te } -func (tl *testListener) cleanup() { - tl.l.Close(canceledContext()) +func (te *testEndpoint) cleanup() { + te.e.Close(canceledContext()) } -func (tl *testListener) wait() { +func (te *testEndpoint) wait() { select { - case tl.idlec <- struct{}{}: - case <-tl.l.closec: + case te.idlec <- struct{}{}: + case <-te.e.closec: } - for _, tc := range tl.conns { + for _, tc := range te.conns { tc.wait() } } -// accept returns a server connection from the listener. -// Unlike Listener.Accept, connections are available as soon as they are created. -func (tl *testListener) accept() *testConn { - if len(tl.acceptQueue) == 0 { - tl.t.Fatalf("accept: expected available conn, but found none") +// accept returns a server connection from the endpoint. +// Unlike Endpoint.Accept, connections are available as soon as they are created. +func (te *testEndpoint) accept() *testConn { + if len(te.acceptQueue) == 0 { + te.t.Fatalf("accept: expected available conn, but found none") } - tc := tl.acceptQueue[0] - tl.acceptQueue = tl.acceptQueue[1:] + tc := te.acceptQueue[0] + te.acceptQueue = te.acceptQueue[1:] return tc } -func (tl *testListener) write(d *datagram) { - tl.recvc <- d - tl.wait() +func (te *testEndpoint) write(d *datagram) { + te.recvc <- d + te.wait() } var testClientAddr = netip.MustParseAddrPort("10.0.0.1:8000") -func (tl *testListener) writeDatagram(d *testDatagram) { - tl.t.Helper() - logDatagram(tl.t, "<- listener under test receives", d) +func (te *testEndpoint) writeDatagram(d *testDatagram) { + te.t.Helper() + logDatagram(te.t, "<- endpoint under test receives", d) var buf []byte for _, p := range d.packets { - tc := tl.connForDestination(p.dstConnID) + tc := te.connForDestination(p.dstConnID) if p.ptype != packetTypeRetry && tc != nil { space := spaceForPacketType(p.ptype) if p.num >= tc.peerNextPacketNum[space] { @@ -171,13 +171,13 @@ func (tl *testListener) writeDatagram(d *testDatagram) { } } if p.ptype == packetTypeInitial { - tl.lastInitialDstConnID = p.dstConnID + te.lastInitialDstConnID = p.dstConnID } pad := 0 if p.ptype == packetType1RTT { pad = d.paddedSize - len(buf) } - buf = append(buf, encodeTestPacket(tl.t, tc, p, pad)...) + buf = append(buf, encodeTestPacket(te.t, tc, p, pad)...) } for len(buf) < d.paddedSize { buf = append(buf, 0) @@ -186,14 +186,14 @@ func (tl *testListener) writeDatagram(d *testDatagram) { if !addr.IsValid() { addr = testClientAddr } - tl.write(&datagram{ + te.write(&datagram{ b: buf, addr: addr, }) } -func (tl *testListener) connForDestination(dstConnID []byte) *testConn { - for _, tc := range tl.conns { +func (te *testEndpoint) connForDestination(dstConnID []byte) *testConn { + for _, tc := range te.conns { for _, loc := range tc.conn.connIDState.local { if bytes.Equal(loc.cid, dstConnID) { return tc @@ -203,8 +203,8 @@ func (tl *testListener) connForDestination(dstConnID []byte) *testConn { return nil } -func (tl *testListener) connForSource(srcConnID []byte) *testConn { - for _, tc := range tl.conns { +func (te *testEndpoint) connForSource(srcConnID []byte) *testConn { + for _, tc := range te.conns { for _, loc := range tc.conn.connIDState.remote { if bytes.Equal(loc.cid, srcConnID) { return tc @@ -214,106 +214,106 @@ func (tl *testListener) connForSource(srcConnID []byte) *testConn { return nil } -func (tl *testListener) read() []byte { - tl.t.Helper() - tl.wait() - if len(tl.sentDatagrams) == 0 { +func (te *testEndpoint) read() []byte { + te.t.Helper() + te.wait() + if len(te.sentDatagrams) == 0 { return nil } - d := tl.sentDatagrams[0] - tl.sentDatagrams = tl.sentDatagrams[1:] + d := te.sentDatagrams[0] + te.sentDatagrams = te.sentDatagrams[1:] return d } -func (tl *testListener) readDatagram() *testDatagram { - tl.t.Helper() - buf := tl.read() +func (te *testEndpoint) readDatagram() *testDatagram { + te.t.Helper() + buf := te.read() if buf == nil { return nil } p, _ := parseGenericLongHeaderPacket(buf) - tc := tl.connForSource(p.dstConnID) - d := parseTestDatagram(tl.t, tl, tc, buf) - logDatagram(tl.t, "-> listener under test sends", d) + tc := te.connForSource(p.dstConnID) + d := parseTestDatagram(te.t, te, tc, buf) + logDatagram(te.t, "-> endpoint under test sends", d) return d } -// wantDatagram indicates that we expect the Listener to send a datagram. -func (tl *testListener) wantDatagram(expectation string, want *testDatagram) { - tl.t.Helper() - got := tl.readDatagram() +// wantDatagram indicates that we expect the Endpoint to send a datagram. +func (te *testEndpoint) wantDatagram(expectation string, want *testDatagram) { + te.t.Helper() + got := te.readDatagram() if !reflect.DeepEqual(got, want) { - tl.t.Fatalf("%v:\ngot datagram: %v\nwant datagram: %v", expectation, got, want) + te.t.Fatalf("%v:\ngot datagram: %v\nwant datagram: %v", expectation, got, want) } } -// wantIdle indicates that we expect the Listener to not send any more datagrams. -func (tl *testListener) wantIdle(expectation string) { - if got := tl.readDatagram(); got != nil { - tl.t.Fatalf("expect: %v\nunexpectedly got: %v", expectation, got) +// wantIdle indicates that we expect the Endpoint to not send any more datagrams. +func (te *testEndpoint) wantIdle(expectation string) { + if got := te.readDatagram(); got != nil { + te.t.Fatalf("expect: %v\nunexpectedly got: %v", expectation, got) } } // advance causes time to pass. -func (tl *testListener) advance(d time.Duration) { - tl.t.Helper() - tl.advanceTo(tl.now.Add(d)) +func (te *testEndpoint) advance(d time.Duration) { + te.t.Helper() + te.advanceTo(te.now.Add(d)) } // advanceTo sets the current time. -func (tl *testListener) advanceTo(now time.Time) { - tl.t.Helper() - if tl.now.After(now) { - tl.t.Fatalf("time moved backwards: %v -> %v", tl.now, now) +func (te *testEndpoint) advanceTo(now time.Time) { + te.t.Helper() + if te.now.After(now) { + te.t.Fatalf("time moved backwards: %v -> %v", te.now, now) } - tl.now = now - for _, tc := range tl.conns { - if !tc.timer.After(tl.now) { + te.now = now + for _, tc := range te.conns { + if !tc.timer.After(te.now) { tc.conn.sendMsg(timerEvent{}) tc.wait() } } } -// testListenerHooks implements listenerTestHooks. -type testListenerHooks testListener +// testEndpointHooks implements endpointTestHooks. +type testEndpointHooks testEndpoint -func (tl *testListenerHooks) timeNow() time.Time { - return tl.now +func (te *testEndpointHooks) timeNow() time.Time { + return te.now } -func (tl *testListenerHooks) newConn(c *Conn) { - tc := newTestConnForConn(tl.t, (*testListener)(tl), c) - tl.conns[c] = tc +func (te *testEndpointHooks) newConn(c *Conn) { + tc := newTestConnForConn(te.t, (*testEndpoint)(te), c) + te.conns[c] = tc } -// testListenerUDPConn implements UDPConn. -type testListenerUDPConn testListener +// testEndpointUDPConn implements UDPConn. +type testEndpointUDPConn testEndpoint -func (tl *testListenerUDPConn) Close() error { - close(tl.recvc) +func (te *testEndpointUDPConn) Close() error { + close(te.recvc) return nil } -func (tl *testListenerUDPConn) LocalAddr() net.Addr { +func (te *testEndpointUDPConn) LocalAddr() net.Addr { return net.UDPAddrFromAddrPort(netip.MustParseAddrPort("127.0.0.1:443")) } -func (tl *testListenerUDPConn) ReadMsgUDPAddrPort(b, control []byte) (n, controln, flags int, _ netip.AddrPort, _ error) { +func (te *testEndpointUDPConn) ReadMsgUDPAddrPort(b, control []byte) (n, controln, flags int, _ netip.AddrPort, _ error) { for { select { - case d, ok := <-tl.recvc: + case d, ok := <-te.recvc: if !ok { return 0, 0, 0, netip.AddrPort{}, io.EOF } n = copy(b, d.b) return n, 0, 0, d.addr, nil - case <-tl.idlec: + case <-te.idlec: } } } -func (tl *testListenerUDPConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (int, error) { - tl.sentDatagrams = append(tl.sentDatagrams, append([]byte(nil), b...)) +func (te *testEndpointUDPConn) WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (int, error) { + te.sentDatagrams = append(te.sentDatagrams, append([]byte(nil), b...)) return len(b), nil } diff --git a/internal/quic/qlog.go b/internal/quic/qlog.go index c8ee429fe..ea53cab1e 100644 --- a/internal/quic/qlog.go +++ b/internal/quic/qlog.go @@ -95,7 +95,7 @@ func (c *Conn) logConnectionStarted(originalDstConnID []byte, peerAddr netip.Add slog.String("type", vantage), ), ) - localAddr := c.listener.LocalAddr() + localAddr := c.endpoint.LocalAddr() // https://www.ietf.org/archive/id/draft-ietf-quic-qlog-quic-events-03.html#section-4.2 c.log.LogAttrs(context.Background(), QLogLevelEndpoint, "connectivity:connection_started", diff --git a/internal/quic/retry.go b/internal/quic/retry.go index e3d9f4d7d..31cb57b88 100644 --- a/internal/quic/retry.go +++ b/internal/quic/retry.go @@ -39,7 +39,7 @@ var ( // retryTokenValidityPeriod is how long we accept a Retry packet token after sending it. const retryTokenValidityPeriod = 5 * time.Second -// retryState generates and validates a listener's retry tokens. +// retryState generates and validates an endpoint's retry tokens. type retryState struct { aead cipher.AEAD } @@ -139,7 +139,7 @@ func (rs *retryState) additionalData(srcConnID []byte, addr netip.AddrPort) []by return additional } -func (l *Listener) validateInitialAddress(now time.Time, p genericLongPacket, addr netip.AddrPort) (origDstConnID []byte, ok bool) { +func (e *Endpoint) validateInitialAddress(now time.Time, p genericLongPacket, addr netip.AddrPort) (origDstConnID []byte, ok bool) { // The retry token is at the start of an Initial packet's data. token, n := consumeUint8Bytes(p.data) if n < 0 { @@ -151,22 +151,22 @@ func (l *Listener) validateInitialAddress(now time.Time, p genericLongPacket, ad if len(token) == 0 { // The sender has not provided a token. // Send a Retry packet to them with one. - l.sendRetry(now, p, addr) + e.sendRetry(now, p, addr) return nil, false } - origDstConnID, ok = l.retry.validateToken(now, token, p.srcConnID, p.dstConnID, addr) + origDstConnID, ok = e.retry.validateToken(now, token, p.srcConnID, p.dstConnID, addr) if !ok { // This does not seem to be a valid token. // Close the connection with an INVALID_TOKEN error. // https://www.rfc-editor.org/rfc/rfc9000#section-8.1.2-5 - l.sendConnectionClose(p, addr, errInvalidToken) + e.sendConnectionClose(p, addr, errInvalidToken) return nil, false } return origDstConnID, true } -func (l *Listener) sendRetry(now time.Time, p genericLongPacket, addr netip.AddrPort) { - token, srcConnID, err := l.retry.makeToken(now, p.srcConnID, p.dstConnID, addr) +func (e *Endpoint) sendRetry(now time.Time, p genericLongPacket, addr netip.AddrPort) { + token, srcConnID, err := e.retry.makeToken(now, p.srcConnID, p.dstConnID, addr) if err != nil { return } @@ -175,7 +175,7 @@ func (l *Listener) sendRetry(now time.Time, p genericLongPacket, addr netip.Addr srcConnID: srcConnID, token: token, }) - l.sendDatagram(b, addr) + e.sendDatagram(b, addr) } type retryPacket struct { diff --git a/internal/quic/retry_test.go b/internal/quic/retry_test.go index f754270a5..4a21a4ca1 100644 --- a/internal/quic/retry_test.go +++ b/internal/quic/retry_test.go @@ -16,7 +16,7 @@ import ( ) type retryServerTest struct { - tl *testListener + te *testEndpoint originalSrcConnID []byte originalDstConnID []byte retry retryPacket @@ -32,16 +32,16 @@ func newRetryServerTest(t *testing.T) *retryServerTest { TLSConfig: newTestTLSConfig(serverSide), RequireAddressValidation: true, } - tl := newTestListener(t, config) + te := newTestEndpoint(t, config) srcID := testPeerConnID(0) dstID := testLocalConnID(-1) params := defaultTransportParameters() params.initialSrcConnID = srcID - initialCrypto := initialClientCrypto(t, tl, params) + initialCrypto := initialClientCrypto(t, te, params) // Initial packet with no Token. // Server responds with a Retry containing a token. - tl.writeDatagram(&testDatagram{ + te.writeDatagram(&testDatagram{ packets: []*testPacket{{ ptype: packetTypeInitial, num: 0, @@ -56,7 +56,7 @@ func newRetryServerTest(t *testing.T) *retryServerTest { }}, paddedSize: 1200, }) - got := tl.readDatagram() + got := te.readDatagram() if len(got.packets) != 1 || got.packets[0].ptype != packetTypeRetry { t.Fatalf("got datagram: %v\nwant Retry", got) } @@ -66,7 +66,7 @@ func newRetryServerTest(t *testing.T) *retryServerTest { } return &retryServerTest{ - tl: tl, + te: te, originalSrcConnID: srcID, originalDstConnID: dstID, retry: retryPacket{ @@ -80,9 +80,9 @@ func newRetryServerTest(t *testing.T) *retryServerTest { func TestRetryServerSucceeds(t *testing.T) { rt := newRetryServerTest(t) - tl := rt.tl - tl.advance(retryTokenValidityPeriod) - tl.writeDatagram(&testDatagram{ + te := rt.te + te.advance(retryTokenValidityPeriod) + te.writeDatagram(&testDatagram{ packets: []*testPacket{{ ptype: packetTypeInitial, num: 1, @@ -98,7 +98,7 @@ func TestRetryServerSucceeds(t *testing.T) { }}, paddedSize: 1200, }) - tc := tl.accept() + tc := te.accept() initial := tc.readPacket() if initial == nil || initial.ptype != packetTypeInitial { t.Fatalf("got packet:\n%v\nwant: Initial", initial) @@ -124,8 +124,8 @@ func TestRetryServerTokenInvalid(t *testing.T) { // INVALID_TOKEN error." // https://www.rfc-editor.org/rfc/rfc9000#section-8.1.2-5 rt := newRetryServerTest(t) - tl := rt.tl - tl.writeDatagram(&testDatagram{ + te := rt.te + te.writeDatagram(&testDatagram{ packets: []*testPacket{{ ptype: packetTypeInitial, num: 1, @@ -141,7 +141,7 @@ func TestRetryServerTokenInvalid(t *testing.T) { }}, paddedSize: 1200, }) - tl.wantDatagram("server closes connection after Initial with invalid Retry token", + te.wantDatagram("server closes connection after Initial with invalid Retry token", initialConnectionCloseDatagram( rt.retry.srcConnID, rt.originalSrcConnID, @@ -152,9 +152,9 @@ func TestRetryServerTokenTooOld(t *testing.T) { // "[...] a token SHOULD have an expiration time [...]" // https://www.rfc-editor.org/rfc/rfc9000#section-8.1.3-3 rt := newRetryServerTest(t) - tl := rt.tl - tl.advance(retryTokenValidityPeriod + time.Second) - tl.writeDatagram(&testDatagram{ + te := rt.te + te.advance(retryTokenValidityPeriod + time.Second) + te.writeDatagram(&testDatagram{ packets: []*testPacket{{ ptype: packetTypeInitial, num: 1, @@ -170,7 +170,7 @@ func TestRetryServerTokenTooOld(t *testing.T) { }}, paddedSize: 1200, }) - tl.wantDatagram("server closes connection after Initial with expired token", + te.wantDatagram("server closes connection after Initial with expired token", initialConnectionCloseDatagram( rt.retry.srcConnID, rt.originalSrcConnID, @@ -182,8 +182,8 @@ func TestRetryServerTokenWrongIP(t *testing.T) { // to verify that the source IP address and port in client packets remain constant." // https://www.rfc-editor.org/rfc/rfc9000#section-8.1.4-3 rt := newRetryServerTest(t) - tl := rt.tl - tl.writeDatagram(&testDatagram{ + te := rt.te + te.writeDatagram(&testDatagram{ packets: []*testPacket{{ ptype: packetTypeInitial, num: 1, @@ -200,7 +200,7 @@ func TestRetryServerTokenWrongIP(t *testing.T) { paddedSize: 1200, addr: netip.MustParseAddrPort("10.0.0.2:8000"), }) - tl.wantDatagram("server closes connection after Initial from wrong address", + te.wantDatagram("server closes connection after Initial from wrong address", initialConnectionCloseDatagram( rt.retry.srcConnID, rt.originalSrcConnID, @@ -435,7 +435,7 @@ func TestRetryClientIgnoresRetryWithInvalidIntegrityTag(t *testing.T) { token: []byte{1, 2, 3, 4}, }) pkt[len(pkt)-1] ^= 1 // invalidate the integrity tag - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: pkt, addr: testClientAddr, }) @@ -527,14 +527,14 @@ func TestParseInvalidRetryPackets(t *testing.T) { } } -func initialClientCrypto(t *testing.T, l *testListener, p transportParameters) []byte { +func initialClientCrypto(t *testing.T, e *testEndpoint, p transportParameters) []byte { t.Helper() config := &tls.QUICConfig{TLSConfig: newTestTLSConfig(clientSide)} tlsClient := tls.QUICClient(config) tlsClient.SetTransportParameters(marshalTransportParameters(p)) tlsClient.Start(context.Background()) //defer tlsClient.Close() - l.peerTLSConn = tlsClient + e.peerTLSConn = tlsClient var data []byte for { e := tlsClient.NextEvent() diff --git a/internal/quic/stateless_reset_test.go b/internal/quic/stateless_reset_test.go index c01375fbd..45a49e81e 100644 --- a/internal/quic/stateless_reset_test.go +++ b/internal/quic/stateless_reset_test.go @@ -68,7 +68,7 @@ func TestStatelessResetSentSizes(t *testing.T) { StatelessResetKey: testStatelessResetKey, } addr := netip.MustParseAddr("127.0.0.1") - tl := newTestListener(t, config) + te := newTestEndpoint(t, config) for i, test := range []struct { reqSize int wantSize int @@ -105,9 +105,9 @@ func TestStatelessResetSentSizes(t *testing.T) { cid := testLocalConnID(int64(i)) token := testStatelessResetToken(cid) addrport := netip.AddrPortFrom(addr, uint16(8000+i)) - tl.write(newDatagramForReset(cid, test.reqSize, addrport)) + te.write(newDatagramForReset(cid, test.reqSize, addrport)) - got := tl.read() + got := te.read() if len(got) != test.wantSize { t.Errorf("got %v-byte response to %v-byte req, want %v", len(got), test.reqSize, test.wantSize) @@ -149,7 +149,7 @@ func TestStatelessResetSuccessfulNewConnectionID(t *testing.T) { resetToken := testPeerStatelessResetToken(1) // provided during handshake dgram := append(make([]byte, 100), resetToken[:]...) - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: dgram, }) @@ -179,7 +179,7 @@ func TestStatelessResetSuccessfulTransportParameter(t *testing.T) { tc.handshake() dgram := append(make([]byte, 100), resetToken[:]...) - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: dgram, }) @@ -243,7 +243,7 @@ func TestStatelessResetSuccessfulPrefix(t *testing.T) { dgram = append(dgram, byte(len(dgram))) // semi-random junk } dgram = append(dgram, resetToken[:]...) - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: dgram, }) if err := tc.conn.Wait(canceledContext()); !errors.Is(err, errStatelessReset) { @@ -278,7 +278,7 @@ func TestStatelessResetRetiredConnID(t *testing.T) { // Receive a stateless reset for connection ID 0. dgram := append(make([]byte, 100), resetToken[:]...) - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: dgram, }) diff --git a/internal/quic/tls_test.go b/internal/quic/tls_test.go index fa339b9fa..14f74a00a 100644 --- a/internal/quic/tls_test.go +++ b/internal/quic/tls_test.go @@ -36,7 +36,7 @@ func (tc *testConn) handshake() { for { if i == len(dgrams)-1 { if tc.conn.side == clientSide { - want := tc.listener.now.Add(maxAckDelay - timerGranularity) + want := tc.endpoint.now.Add(maxAckDelay - timerGranularity) if !tc.timer.Equal(want) { t.Fatalf("want timer = %v (max_ack_delay), got %v", want, tc.timer) } @@ -85,7 +85,7 @@ func handshakeDatagrams(tc *testConn) (dgrams []*testDatagram) { testPeerConnID(0), testPeerConnID(1), } - localResetToken := tc.listener.l.resetGen.tokenForConnID(localConnIDs[1]) + localResetToken := tc.endpoint.e.resetGen.tokenForConnID(localConnIDs[1]) peerResetToken := testPeerStatelessResetToken(1) if tc.conn.side == clientSide { clientConnIDs = localConnIDs diff --git a/internal/quic/version_test.go b/internal/quic/version_test.go index 830e0e1c8..92fabd7b3 100644 --- a/internal/quic/version_test.go +++ b/internal/quic/version_test.go @@ -17,7 +17,7 @@ func TestVersionNegotiationServerReceivesUnknownVersion(t *testing.T) { config := &Config{ TLSConfig: newTestTLSConfig(serverSide), } - tl := newTestListener(t, config) + te := newTestEndpoint(t, config) // Packet of unknown contents for some unrecognized QUIC version. dstConnID := []byte{1, 2, 3, 4} @@ -34,10 +34,10 @@ func TestVersionNegotiationServerReceivesUnknownVersion(t *testing.T) { pkt = append(pkt, 0) } - tl.write(&datagram{ + te.write(&datagram{ b: pkt, }) - gotPkt := tl.read() + gotPkt := te.read() if gotPkt == nil { t.Fatalf("got no response; want Version Negotiaion") } @@ -59,7 +59,7 @@ func TestVersionNegotiationServerReceivesUnknownVersion(t *testing.T) { func TestVersionNegotiationClientAborts(t *testing.T) { tc := newTestConn(t, clientSide) p := tc.readPacket() // client Initial packet - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: appendVersionNegotiation(nil, p.srcConnID, p.dstConnID, 10), }) tc.wantIdle("connection does not send a CONNECTION_CLOSE") @@ -76,7 +76,7 @@ func TestVersionNegotiationClientIgnoresAfterProcessingPacket(t *testing.T) { debugFrameCrypto{ data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], }) - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: appendVersionNegotiation(nil, p.srcConnID, p.dstConnID, 10), }) if err := tc.conn.waitReady(canceledContext()); err != context.Canceled { @@ -94,7 +94,7 @@ func TestVersionNegotiationClientIgnoresMismatchingSourceConnID(t *testing.T) { tc := newTestConn(t, clientSide) tc.ignoreFrame(frameTypeAck) p := tc.readPacket() // client Initial packet - tc.listener.write(&datagram{ + tc.endpoint.write(&datagram{ b: appendVersionNegotiation(nil, p.srcConnID, []byte("mismatch"), 10), }) tc.writeFrames(packetTypeInitial,