package quic

import (
	
	
	
	
	
	
	

	
	
	
	
	
	
	
	
)

// ErrServerClosed is returned by the [Listener] or [EarlyListener]'s Accept method after a call to Close.
var ErrServerClosed = errServerClosed{}

type errServerClosed struct{}

func (errServerClosed) () string { return "quic: server closed" }
func (errServerClosed) () error { return net.ErrClosed }

// packetHandler handles packets
type packetHandler interface {
	handlePacket(receivedPacket)
	destroy(error)
	closeWithTransportError(qerr.TransportErrorCode)
}

type zeroRTTQueue struct {
	packets    []receivedPacket
	expiration monotime.Time
}

type rejectedPacket struct {
	receivedPacket
	hdr *wire.Header
}

// A Listener of QUIC
type baseServer struct {
	tr                        *packetHandlerMap
	disableVersionNegotiation bool
	acceptEarlyConns          bool

	tlsConf *tls.Config
	config  *Config

	conn rawConn

	tokenGenerator *handshake.TokenGenerator
	maxTokenAge    time.Duration

	connIDGenerator   ConnectionIDGenerator
	statelessResetter *statelessResetter
	onClose           func()

	receivedPackets chan receivedPacket

	nextZeroRTTCleanup monotime.Time
	zeroRTTQueues      map[protocol.ConnectionID]*zeroRTTQueue // only initialized if acceptEarlyConns == true

	connContext func(context.Context, *ClientInfo) (context.Context, error)

	// set as a member, so they can be set in the tests
	newConn func(
		context.Context,
		context.CancelCauseFunc,
		sendConn,
		connRunner,
		protocol.ConnectionID, /* original dest connection ID */
		*protocol.ConnectionID, /* retry src connection ID */
		protocol.ConnectionID, /* client dest connection ID */
		protocol.ConnectionID, /* destination connection ID */
		protocol.ConnectionID, /* source connection ID */
		ConnectionIDGenerator,
		*statelessResetter,
		*Config,
		*tls.Config,
		*handshake.TokenGenerator,
		bool, /* client address validated by an address validation token */
		time.Duration,
		qlogwriter.Trace,
		utils.Logger,
		protocol.Version,
	) *wrappedConn

	closeMx sync.Mutex
	// errorChan is closed when Close is called. This has two effects:
	// 1. it cancels handshakes that are still in flight (using CONNECTION_REFUSED) errors
	// 2. it stops handling of packets passed to this server
	errorChan chan struct{}
	// acceptChan is closed when Close returns.
	// This only happens once all handshake in flight have either completed and canceled.
	// Calls to Accept will first drain the queue of connections that have completed the handshake,
	// and then return ErrServerClosed.
	stopAccepting chan struct{}
	closeErr      error
	running       chan struct{} // closed as soon as run() returns

	versionNegotiationQueue chan receivedPacket
	invalidTokenQueue       chan rejectedPacket
	connectionRefusedQueue  chan rejectedPacket
	retryQueue              chan rejectedPacket
	handshakingCount        sync.WaitGroup

	verifySourceAddress func(net.Addr) bool

	connQueue chan *Conn

	qlogger qlogwriter.Recorder

	logger utils.Logger
}

// A Listener listens for incoming QUIC connections.
// It returns connections once the handshake has completed.
type Listener struct {
	baseServer *baseServer
}

// Accept returns new connections. It should be called in a loop.
func ( *Listener) ( context.Context) (*Conn, error) {
	return .baseServer.Accept()
}

// Close closes the listener.
// Accept will return [ErrServerClosed] as soon as all connections in the accept queue have been accepted.
// QUIC handshakes that are still in flight will be rejected with a CONNECTION_REFUSED error.
// Already established (accepted) connections will be unaffected.
func ( *Listener) () error {
	return .baseServer.Close()
}

// Addr returns the local network address that the server is listening on.
func ( *Listener) () net.Addr {
	return .baseServer.Addr()
}

// An EarlyListener listens for incoming QUIC connections, and returns them before the handshake completes.
// For connections that don't use 0-RTT, this allows the server to send 0.5-RTT data.
// This data is encrypted with forward-secure keys, however, the client's identity has not yet been verified.
// For connection using 0-RTT, this allows the server to accept and respond to streams that the client opened in the
// 0-RTT data it sent. Note that at this point during the handshake, the live-ness of the
// client has not yet been confirmed, and the 0-RTT data could have been replayed by an attacker.
type EarlyListener struct {
	baseServer *baseServer
}

// Accept returns a new connections. It should be called in a loop.
func ( *EarlyListener) ( context.Context) (*Conn, error) {
	,  := .baseServer.accept()
	if  != nil {
		return nil, 
	}
	return , nil
}

// Close closes the listener.
// Accept will return [ErrServerClosed] as soon as all connections in the accept queue have been accepted.
// Early connections that are still in flight will be rejected with a CONNECTION_REFUSED error.
// Already established (accepted) connections will be unaffected.
func ( *EarlyListener) () error {
	return .baseServer.Close()
}

// Addr returns the local network addr that the server is listening on.
func ( *EarlyListener) () net.Addr {
	return .baseServer.Addr()
}

// ListenAddr creates a QUIC server listening on a given address.
// See [Listen] for more details.
func ( string,  *tls.Config,  *Config) (*Listener, error) {
	,  := listenUDP()
	if  != nil {
		return nil, 
	}
	return (&Transport{
		Conn:        ,
		createdConn: true,
		isSingleUse: true,
	}).Listen(, )
}

// ListenAddrEarly works like [ListenAddr], but it returns connections before the handshake completes.
func ( string,  *tls.Config,  *Config) (*EarlyListener, error) {
	,  := listenUDP()
	if  != nil {
		return nil, 
	}
	return (&Transport{
		Conn:        ,
		createdConn: true,
		isSingleUse: true,
	}).ListenEarly(, )
}

func listenUDP( string) (*net.UDPConn, error) {
	,  := net.ResolveUDPAddr("udp", )
	if  != nil {
		return nil, 
	}
	return net.ListenUDP("udp", )
}

// Listen listens for QUIC connections on a given net.PacketConn.
// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does),
// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
// will be used instead of ReadFrom and WriteTo to read/write packets.
// A single net.PacketConn can only be used for a single call to Listen.
//
// The tls.Config must not be nil and must contain a certificate configuration.
// Furthermore, it must define an application control (using [NextProtos]).
// The quic.Config may be nil, in that case the default values will be used.
//
// This is a convenience function. More advanced use cases should instantiate a [Transport],
// which offers configuration options for a more fine-grained control of the connection establishment,
// including reusing the underlying UDP socket for outgoing QUIC connections.
// When closing a listener created with Listen, all established QUIC connections will be closed immediately.
func ( net.PacketConn,  *tls.Config,  *Config) (*Listener, error) {
	 := &Transport{Conn: , isSingleUse: true}
	return .Listen(, )
}

// ListenEarly works like [Listen], but it returns connections before the handshake completes.
func ( net.PacketConn,  *tls.Config,  *Config) (*EarlyListener, error) {
	 := &Transport{Conn: , isSingleUse: true}
	return .ListenEarly(, )
}

func newServer(
	 rawConn,
	 *packetHandlerMap,
	 ConnectionIDGenerator,
	 *statelessResetter,
	 func(context.Context, *ClientInfo) (context.Context, error),
	 *tls.Config,
	 *Config,
	 qlogwriter.Recorder,
	 func(),
	 TokenGeneratorKey,
	 time.Duration,
	 func(net.Addr) bool,
	 bool,
	 bool,
) *baseServer {
	 := &baseServer{
		conn:                      ,
		connContext:               ,
		tr:                        ,
		tlsConf:                   ,
		config:                    ,
		tokenGenerator:            handshake.NewTokenGenerator(),
		maxTokenAge:               ,
		verifySourceAddress:       ,
		connIDGenerator:           ,
		statelessResetter:         ,
		connQueue:                 make(chan *Conn, protocol.MaxAcceptQueueSize),
		errorChan:                 make(chan struct{}),
		stopAccepting:             make(chan struct{}),
		running:                   make(chan struct{}),
		receivedPackets:           make(chan receivedPacket, protocol.MaxServerUnprocessedPackets),
		versionNegotiationQueue:   make(chan receivedPacket, 4),
		invalidTokenQueue:         make(chan rejectedPacket, 4),
		connectionRefusedQueue:    make(chan rejectedPacket, 4),
		retryQueue:                make(chan rejectedPacket, 8),
		newConn:                   newConnection,
		qlogger:                   ,
		logger:                    utils.DefaultLogger.WithPrefix("server"),
		acceptEarlyConns:          ,
		disableVersionNegotiation: ,
		onClose:                   ,
	}
	if  {
		.zeroRTTQueues = map[protocol.ConnectionID]*zeroRTTQueue{}
	}
	go .run()
	go .runSendQueue()
	.logger.Debugf("Listening for %s connections on %s", .LocalAddr().Network(), .LocalAddr().String())
	return 
}

func ( *baseServer) () {
	defer close(.running)
	for {
		select {
		case <-.errorChan:
			return
		default:
		}
		select {
		case <-.errorChan:
			return
		case  := <-.receivedPackets:
			if  := .handlePacketImpl(); ! {
				.buffer.Release()
			}
		}
	}
}

func ( *baseServer) () {
	for {
		select {
		case <-.running:
			return
		case  := <-.versionNegotiationQueue:
			.maybeSendVersionNegotiationPacket()
		case  := <-.invalidTokenQueue:
			.maybeSendInvalidToken()
		case  := <-.connectionRefusedQueue:
			.sendConnectionRefused()
		case  := <-.retryQueue:
			.sendRetry()
		}
	}
}

// Accept returns connections that already completed the handshake.
// It is only valid if acceptEarlyConns is false.
func ( *baseServer) ( context.Context) (*Conn, error) {
	return .accept()
}

func ( *baseServer) ( context.Context) (*Conn, error) {
	select {
	case <-.Done():
		return nil, .Err()
	case  := <-.connQueue:
		return , nil
	case <-.stopAccepting:
		// first drain the queue
		select {
		case  := <-.connQueue:
			return , nil
		default:
		}
		return nil, .closeErr
	}
}

func ( *baseServer) () error {
	.close(ErrServerClosed, false)
	return nil
}

// close closes the server. The Transport mutex must not be held while calling this method.
// This method closes any handshaking connections which requires the tranpsort mutex.
func ( *baseServer) ( error,  bool) {
	.closeMx.Lock()
	if .closeErr != nil {
		.closeMx.Unlock()
		return
	}
	.closeErr = 
	close(.errorChan)
	<-.running
	.closeMx.Unlock()

	if ! {
		.onClose()
	}

	// wait until all handshakes in flight have terminated
	.handshakingCount.Wait()
	close(.stopAccepting)

	if  {
		// if the transport is closing, drain the connQueue. All connections in the queue
		// will be closed by the transport.
		for {
			select {
			case <-.connQueue:
			default:
				return
			}
		}
	}
}

// Addr returns the server's network address
func ( *baseServer) () net.Addr {
	return .conn.LocalAddr()
}

func ( *baseServer) ( receivedPacket) {
	select {
	case .receivedPackets <- :
	case <-.errorChan:
		return
	default:
		.logger.Debugf("Dropping packet from %s (%d bytes). Server receive queue full.", .remoteAddr, .Size())
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropDOSPrevention,
			})
		}
	}
}

func ( *baseServer) ( receivedPacket) bool /* is the buffer still in use? */ {
	if !.nextZeroRTTCleanup.IsZero() && .rcvTime.After(.nextZeroRTTCleanup) {
		defer .cleanupZeroRTTQueues(.rcvTime)
	}

	if wire.IsVersionNegotiationPacket(.data) {
		.logger.Debugf("Dropping Version Negotiation packet.")
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header:  qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		return false
	}
	// Short header packets should never end up here in the first place
	if !wire.IsLongHeaderPacket(.data[0]) {
		panic(fmt.Sprintf("misrouted packet: %#v", .data))
	}
	,  := wire.ParseVersion(.data)
	// drop the packet if we failed to parse the protocol version
	if  != nil {
		.logger.Debugf("Dropping a packet with an unknown version")
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		return false
	}
	// send a Version Negotiation Packet if the client is speaking a different protocol version
	if !protocol.IsSupportedVersion(.config.Versions, ) {
		if .disableVersionNegotiation {
			if .qlogger != nil {
				.qlogger.RecordEvent(qlog.PacketDropped{
					Header:  qlog.PacketHeader{Version: },
					Raw:     qlog.RawInfo{Length: int(.Size())},
					Trigger: qlog.PacketDropUnexpectedVersion,
				})
			}
			return false
		}

		if .Size() < protocol.MinUnknownVersionPacketSize {
			.logger.Debugf("Dropping a packet with an unsupported version number %d that is too small (%d bytes)", , .Size())
			if .qlogger != nil {
				.qlogger.RecordEvent(qlog.PacketDropped{
					Header:  qlog.PacketHeader{Version: },
					Raw:     qlog.RawInfo{Length: int(.Size())},
					Trigger: qlog.PacketDropUnexpectedPacket,
				})
			}
			return false
		}
		return .enqueueVersionNegotiationPacket()
	}

	if wire.Is0RTTPacket(.data) {
		if !.acceptEarlyConns {
			if .qlogger != nil {
				.qlogger.RecordEvent(qlog.PacketDropped{
					Header: qlog.PacketHeader{
						PacketType:   qlog.PacketType0RTT,
						PacketNumber: protocol.InvalidPacketNumber,
					},
					Raw:     qlog.RawInfo{Length: int(.Size())},
					Trigger: qlog.PacketDropUnexpectedPacket,
				})
			}
			return false
		}
		return .handle0RTTPacket()
	}

	// If we're creating a new connection, the packet will be passed to the connection.
	// The header will then be parsed again.
	, , ,  := wire.ParsePacket(.data)
	if  != nil {
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropHeaderParseError,
			})
		}
		.logger.Debugf("Error parsing packet: %s", )
		return false
	}
	if .Type == protocol.PacketTypeInitial && .Size() < protocol.MinInitialPacketSize {
		.logger.Debugf("Dropping a packet that is too small to be a valid Initial (%d bytes)", .Size())
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketTypeInitial,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      ,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		return false
	}

	if .Type != protocol.PacketTypeInitial {
		// Drop long header packets.
		// There's little point in sending a Stateless Reset, since the client
		// might not have received the token yet.
		.logger.Debugf("Dropping long header packet of type %s (%d bytes)", .Type, len(.data))
		if .qlogger != nil {
			var  qlog.PacketType
			switch .Type {
			case protocol.PacketTypeInitial:
				 = qlog.PacketTypeInitial
			case protocol.PacketTypeHandshake:
				 = qlog.PacketTypeHandshake
			case protocol.PacketType0RTT:
				 = qlog.PacketType0RTT
			case protocol.PacketTypeRetry:
				 = qlog.PacketTypeRetry
			}
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   ,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      ,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		return false
	}

	.logger.Debugf("<- Received Initial packet.")

	if  := .handleInitialImpl(, );  != nil {
		.logger.Errorf("Error occurred handling initial packet: %s", )
	}
	// Don't put the packet buffer back.
	// handleInitialImpl deals with the buffer.
	return true
}

func ( *baseServer) ( receivedPacket) bool {
	,  := wire.ParseConnectionID(.data, 0)
	if  != nil {
		if .qlogger != nil {
			,  := wire.ParseVersion(.data)
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketType0RTT,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      ,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropHeaderParseError,
			})
		}
		return false
	}

	// check again if we might have a connection now
	if ,  := .tr.Get();  {
		.handlePacket()
		return true
	}

	if ,  := .zeroRTTQueues[];  {
		if len(.packets) >= protocol.Max0RTTQueueLen {
			if .qlogger != nil {
				,  := wire.ParseVersion(.data)
				.qlogger.RecordEvent(qlog.PacketDropped{
					Header: qlog.PacketHeader{
						PacketType:   qlog.PacketType0RTT,
						PacketNumber: protocol.InvalidPacketNumber,
						Version:      ,
					},
					Raw:     qlog.RawInfo{Length: int(.Size())},
					Trigger: qlog.PacketDropDOSPrevention,
				})
			}
			return false
		}
		.packets = append(.packets, )
		return true
	}

	if len(.zeroRTTQueues) >= protocol.Max0RTTQueues {
		if .qlogger != nil {
			,  := wire.ParseVersion(.data)
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketType0RTT,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      ,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropDOSPrevention,
			})
		}
		return false
	}
	 := &zeroRTTQueue{packets: make([]receivedPacket, 1, 8)}
	.packets[0] = 
	 := .rcvTime.Add(protocol.Max0RTTQueueingDuration)
	.expiration = 
	if .nextZeroRTTCleanup.IsZero() || .nextZeroRTTCleanup.After() {
		.nextZeroRTTCleanup = 
	}
	.zeroRTTQueues[] = 
	return true
}

func ( *baseServer) ( monotime.Time) {
	// Iterate over all queues to find those that are expired.
	// This is ok since we're placing a pretty low limit on the number of queues.
	var  monotime.Time
	for ,  := range .zeroRTTQueues {
		if .expiration.After() {
			if .IsZero() || .After(.expiration) {
				 = .expiration
			}
			continue
		}
		for ,  := range .packets {
			if .qlogger != nil {
				,  := wire.ParseVersion(.data)
				.qlogger.RecordEvent(qlog.PacketDropped{
					Header: qlog.PacketHeader{
						PacketType:   qlog.PacketType0RTT,
						PacketNumber: protocol.InvalidPacketNumber,
						Version:      ,
					},
					Raw:     qlog.RawInfo{Length: int(.Size())},
					Trigger: qlog.PacketDropDOSPrevention,
				})
			}
			.buffer.Release()
		}
		delete(.zeroRTTQueues, )
		if .logger.Debug() {
			.logger.Debugf("Removing 0-RTT queue for %s.", )
		}
	}
	.nextZeroRTTCleanup = 
}

// validateToken returns false if:
//   - address is invalid
//   - token is expired
//   - token is null
func ( *baseServer) ( *handshake.Token,  net.Addr) bool {
	if  == nil {
		return false
	}
	if !.ValidateRemoteAddr() {
		return false
	}
	if !.IsRetryToken && time.Since(.SentTime) > .maxTokenAge {
		return false
	}
	if .IsRetryToken && time.Since(.SentTime) > .config.maxRetryTokenAge() {
		return false
	}
	return true
}

func ( *baseServer) ( receivedPacket,  *wire.Header) error {
	if len(.Token) == 0 && .DestConnectionID.Len() < protocol.MinConnectionIDLenInitial {
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketTypeInitial,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      .Version,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		.buffer.Release()
		return errors.New("too short connection ID")
	}

	// The server queues packets for a while, and we might already have established a connection by now.
	// This results in a second check in the connection map.
	// That's ok since it's not the hot path (it's only taken by some Initial and 0-RTT packets).
	if ,  := .tr.Get(.DestConnectionID);  {
		.handlePacket()
		return nil
	}

	var (
		              *handshake.Token
		     *protocol.ConnectionID
		 bool
	)
	 := .DestConnectionID
	if len(.Token) > 0 {
		,  := .tokenGenerator.DecodeToken(.Token)
		if  == nil {
			if .IsRetryToken {
				 = .OriginalDestConnectionID
				 = &.RetrySrcConnectionID
			}
			 = 
		}
	}
	if  != nil {
		 = .validateToken(, .remoteAddr)
		if ! {
			// For invalid and expired non-retry tokens, we don't send an INVALID_TOKEN error.
			// We just ignore them, and act as if there was no token on this packet at all.
			// This also means we might send a Retry later.
			if !.IsRetryToken {
				 = nil
			} else {
				// For Retry tokens, we send an INVALID_ERROR if
				// * the token is too old, or
				// * the token is invalid, in case of a retry token.
				select {
				case .invalidTokenQueue <- rejectedPacket{receivedPacket: , hdr: }:
				default:
					// drop packet if we can't send out the  INVALID_TOKEN packets fast enough
					.buffer.Release()
				}
				return nil
			}
		}
	}

	if  == nil && .verifySourceAddress != nil && .verifySourceAddress(.remoteAddr) {
		// Retry invalidates all 0-RTT packets sent.
		delete(.zeroRTTQueues, .DestConnectionID)
		select {
		case .retryQueue <- rejectedPacket{receivedPacket: , hdr: }:
		default:
			// drop packet if we can't send out Retry packets fast enough
			.buffer.Release()
		}
		return nil
	}

	// restore RTT from token
	var  time.Duration
	if  != nil && !.IsRetryToken {
		 = .RTT
	}

	 := .config
	 := &ClientInfo{
		RemoteAddr:   .remoteAddr,
		AddrVerified: ,
	}
	if .config.GetConfigForClient != nil {
		,  := .config.GetConfigForClient()
		if  != nil {
			.logger.Debugf("Rejecting new connection due to GetConfigForClient callback")
			.refuseNewConn(, )
			return nil
		}
		 = populateConfig()
	}

	var  *wrappedConn
	var  context.CancelCauseFunc
	,  := context.WithCancelCause(context.Background())
	if .connContext != nil {
		var  error
		,  = .connContext(, )
		if  != nil {
			()
			.logger.Debugf("Rejecting new connection due to ConnContext callback: %s", )
			.refuseNewConn(, )
			return nil
		}
		if  == nil {
			panic("quic: ConnContext returned nil")
		}
		// There's no guarantee that the application returns a context
		// that's derived from the context we passed into ConnContext.
		// We need to make sure that both contexts are cancelled.
		var  context.CancelCauseFunc
		,  = context.WithCancelCause()
		 = func( error) {
			()
			()
		}
	} else {
		 = 
	}
	var  qlogwriter.Trace
	if .Tracer != nil {
		// Use the same connection ID that is passed to the client's GetLogWriter callback.
		 := .DestConnectionID
		if .Len() > 0 {
			 = 
		}
		 = .Tracer(, false, )
	}
	,  := .connIDGenerator.GenerateConnectionID()
	if  != nil {
		return 
	}
	.logger.Debugf("Changing connection ID to %s.", )
	 = .newConn(
		,
		,
		newSendConn(.conn, .remoteAddr, .info, .logger),
		.tr,
		,
		,
		.DestConnectionID,
		.SrcConnectionID,
		,
		.connIDGenerator,
		.statelessResetter,
		,
		.tlsConf,
		.tokenGenerator,
		,
		,
		,
		.logger,
		.Version,
	)
	.handlePacket()
	// Adding the connection will fail if the client's chosen Destination Connection ID is already in use.
	// This is very unlikely: Even if an attacker chooses a connection ID that's already in use,
	// under normal circumstances the packet would just be routed to that connection.
	// The only time this collision will occur if we receive the two Initial packets at the same time.
	if  := .tr.AddWithConnID(.DestConnectionID, , ); ! {
		delete(.zeroRTTQueues, .DestConnectionID)
		.closeWithTransportError(ConnectionRefused)
		return nil
	}
	// Pass queued 0-RTT to the newly established connection.
	if ,  := .zeroRTTQueues[.DestConnectionID];  {
		for ,  := range .packets {
			.handlePacket()
		}
		delete(.zeroRTTQueues, .DestConnectionID)
	}

	.handshakingCount.Add(1)
	go func() {
		defer .handshakingCount.Done()
		.handleNewConn()
	}()
	go .run()
	return nil
}

func ( *baseServer) ( receivedPacket,  *wire.Header) {
	delete(.zeroRTTQueues, .DestConnectionID)
	select {
	case .connectionRefusedQueue <- rejectedPacket{receivedPacket: , hdr: }:
	default:
		// drop packet if we can't send out the CONNECTION_REFUSED fast enough
		.buffer.Release()
	}
}

func ( *baseServer) ( *wrappedConn) {
	if .acceptEarlyConns {
		// wait until the early connection is ready, the handshake fails, or the server is closed
		select {
		case <-.errorChan:
			.closeWithTransportError(ConnectionRefused)
			return
		case <-.Context().Done():
			return
		case <-.earlyConnReady():
		}
	} else {
		// wait until the handshake completes, fails, or the server is closed
		select {
		case <-.errorChan:
			.closeWithTransportError(ConnectionRefused)
			return
		case <-.Context().Done():
			return
		case <-.HandshakeComplete():
		}
	}

	select {
	case .connQueue <- .Conn:
	default:
		.closeWithTransportError(ConnectionRefused)
	}
}

func ( *baseServer) ( rejectedPacket) {
	if  := .sendRetryPacket();  != nil {
		.logger.Debugf("Error sending Retry packet: %s", )
	}
}

func ( *baseServer) ( rejectedPacket) error {
	 := .hdr
	// Log the Initial packet now.
	// If no Retry is sent, the packet will be logged by the connection.
	(&wire.ExtendedHeader{Header: *}).Log(.logger)
	,  := .connIDGenerator.GenerateConnectionID()
	if  != nil {
		return 
	}
	,  := .tokenGenerator.NewRetryToken(.remoteAddr, .DestConnectionID, )
	if  != nil {
		return 
	}
	 := &wire.ExtendedHeader{}
	.Type = protocol.PacketTypeRetry
	.Version = .Version
	.SrcConnectionID = 
	.DestConnectionID = .SrcConnectionID
	.Token = 
	if .logger.Debug() {
		.logger.Debugf("Changing connection ID to %s.", )
		.logger.Debugf("-> Sending Retry")
		.Log(.logger)
	}

	 := getPacketBuffer()
	defer .Release()
	.Data,  = .Append(.Data, .Version)
	if  != nil {
		return 
	}
	// append the Retry integrity tag
	 := handshake.GetRetryIntegrityTag(.Data, .DestConnectionID, .Version)
	.Data = append(.Data, [:]...)
	if .qlogger != nil {
		.qlogger.RecordEvent(qlog.PacketSent{
			Header: qlog.PacketHeader{
				PacketType:       qlog.PacketTypeRetry,
				SrcConnectionID:  .SrcConnectionID,
				DestConnectionID: .DestConnectionID,
				Version:          .Version,
				Token:            &qlog.Token{Raw: },
			},
			Raw: qlog.RawInfo{
				Length:        len(.Data),
				PayloadLength: int(.Length),
			},
		})
	}
	_,  = .conn.WritePacket(.Data, .remoteAddr, .info.OOB(), 0, protocol.ECNUnsupported)
	return 
}

func ( *baseServer) ( rejectedPacket) {
	defer .buffer.Release()

	// Only send INVALID_TOKEN if we can unprotect the packet.
	// This makes sure that we won't send it for packets that were corrupted.
	 := .hdr
	,  := handshake.NewInitialAEAD(.DestConnectionID, protocol.PerspectiveServer, .Version)
	 := .data[:.ParsedLen()+.Length]
	,  := unpackLongHeader(, , )
	// Only send INVALID_TOKEN if we can unprotect the packet.
	// This makes sure that we won't send it for packets that were corrupted.
	if  != nil {
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketTypeInitial,
					PacketNumber: protocol.InvalidPacketNumber,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropHeaderParseError,
			})
		}
		return
	}
	 := .ParsedLen()
	if ,  := .Open([:], [:], .PacketNumber, [:]);  != nil {
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Header: qlog.PacketHeader{
					PacketType:   qlog.PacketTypeInitial,
					PacketNumber: protocol.InvalidPacketNumber,
					Version:      .Version,
				},
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropPayloadDecryptError,
			})
		}
		return
	}
	if .logger.Debug() {
		.logger.Debugf("Client sent an invalid retry token. Sending INVALID_TOKEN to %s.", .remoteAddr)
	}
	if  := .sendError(.remoteAddr, , , InvalidToken, .info);  != nil {
		.logger.Debugf("Error sending INVALID_TOKEN error: %s", )
	}
}

func ( *baseServer) ( rejectedPacket) {
	defer .buffer.Release()
	,  := handshake.NewInitialAEAD(.hdr.DestConnectionID, protocol.PerspectiveServer, .hdr.Version)
	if  := .sendError(.remoteAddr, .hdr, , ConnectionRefused, .info);  != nil {
		.logger.Debugf("Error sending CONNECTION_REFUSED error: %s", )
	}
}

// sendError sends the error as a response to the packet received with header hdr
func ( *baseServer) ( net.Addr,  *wire.Header,  handshake.LongHeaderSealer,  qerr.TransportErrorCode,  packetInfo) error {
	 := getPacketBuffer()
	defer .Release()

	 := &wire.ConnectionCloseFrame{ErrorCode: uint64()}

	 := &wire.ExtendedHeader{}
	.Type = protocol.PacketTypeInitial
	.Version = .Version
	.SrcConnectionID = .DestConnectionID
	.DestConnectionID = .SrcConnectionID
	.PacketNumberLen = protocol.PacketNumberLen4
	.Length = 4 /* packet number len */ + .Length(.Version) + protocol.ByteCount(.Overhead())
	var  error
	.Data,  = .Append(.Data, .Version)
	if  != nil {
		return 
	}
	 := len(.Data)

	.Data,  = .Append(.Data, .Version)
	if  != nil {
		return 
	}

	_ = .Seal(.Data[:], .Data[:], .PacketNumber, .Data[:])
	.Data = .Data[0 : len(.Data)+.Overhead()]

	 :=  - int(.PacketNumberLen)
	.EncryptHeader(
		.Data[+4:+4+16],
		&.Data[0],
		.Data[:],
	)

	.Log(.logger)
	wire.LogFrame(.logger, , true)
	if .qlogger != nil {
		.qlogger.RecordEvent(qlog.PacketSent{
			Header: qlog.PacketHeader{
				PacketType:       qlog.PacketTypeInitial,
				SrcConnectionID:  .SrcConnectionID,
				DestConnectionID: .DestConnectionID,
				PacketNumber:     .PacketNumber,
				Version:          .Version,
			},
			Raw: qlog.RawInfo{
				Length:        len(.Data),
				PayloadLength: int(.Length),
			},
			Frames: []qlog.Frame{{Frame: }},
		})
	}
	_,  = .conn.WritePacket(.Data, , .OOB(), 0, protocol.ECNUnsupported)
	return 
}

func ( *baseServer) ( receivedPacket) ( bool) {
	select {
	case .versionNegotiationQueue <- :
		return true
	default:
		// it's fine to not send version negotiation packets when we are busy
	}
	return false
}

func ( *baseServer) ( receivedPacket) {
	defer .buffer.Release()

	,  := wire.ParseVersion(.data)
	if  != nil {
		.logger.Debugf("failed to parse version for sending version negotiation packet: %s", )
		return
	}

	, , ,  := wire.ParseArbitraryLenConnectionIDs(.data)
	if  != nil { // should never happen
		.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
		if .qlogger != nil {
			.qlogger.RecordEvent(qlog.PacketDropped{
				Raw:     qlog.RawInfo{Length: int(.Size())},
				Trigger: qlog.PacketDropUnexpectedPacket,
			})
		}
		return
	}

	.logger.Debugf("Client offered version %s, sending Version Negotiation", )

	 := wire.ComposeVersionNegotiation(, , .config.Versions)
	if .qlogger != nil {
		.qlogger.RecordEvent(qlog.VersionNegotiationSent{
			Header: qlog.PacketHeaderVersionNegotiation{
				SrcConnectionID:  ,
				DestConnectionID: ,
			},
			SupportedVersions: .config.Versions,
		})
	}
	if ,  := .conn.WritePacket(, .remoteAddr, .info.OOB(), 0, protocol.ECNUnsupported);  != nil {
		.logger.Debugf("Error sending Version Negotiation: %s", )
	}
}