Repository: caddyserver/caddy
File: listeners.go (Go)

Code before:
	}

	sql := sharedEarlyListener.(*sharedQuicListener)
	// add current tls.Config to sqs, so GetConfigForClient will always return the latest tls.Config in case of context cancellation
	ctx, cancel := sql.sqs.addState(tlsConf)

	return &fakeCloseQuicListener{
		sharedQuicListener: sql,
		context:            ctx,
		contextCancel:      cancel,
	}, nil
}

// ListenerUsage returns the current usage count of the given listener address.
func ListenerUsage(network, addr string) int {
	count, _ := listenerPool.References(listenerKey(network, addr))
	return count
}

// contextAndCancelFunc groups context and its cancelFunc
type contextAndCancelFunc struct {
	context.Context
	context.CancelFunc
}

// sharedQUICState manages GetConfigForClient
// see issue: https://github.com/caddyserver/caddy/pull/4849
type sharedQUICState struct {
	rmu           sync.RWMutex
	tlsConfs      map[*tls.Config]contextAndCancelFunc
	activeTlsConf *tls.Config
}

// newSharedQUICState creates a new sharedQUICState
func newSharedQUICState(tlsConfig *tls.Config) *sharedQUICState {
	sqtc := &sharedQUICState{
		tlsConfs:      make(map[*tls.Config]contextAndCancelFunc),
		activeTlsConf: tlsConfig,
	}
	sqtc.addState(tlsConfig)
	return sqtc
}

// getConfigForClient is used as tls.Config's GetConfigForClient field
func (sqs *sharedQUICState) getConfigForClient(ch *tls.ClientHelloInfo) (*tls.Config, error) {
	sqs.rmu.RLock()
	defer sqs.rmu.RUnlock()
	return sqs.activeTlsConf.GetConfigForClient(ch)
}

// addState adds tls.Config and activeRequests to the map if not present and returns the corresponding context and its cancelFunc

Review comment (suggestion):
I would use variadic parameters `...PacketConnWrapper` so that callers won't have to change anything if no packet conn wrappers are present.

Code after:
// address string of the form accepted by ParseNetworkAddress(). For
// unix sockets, the network should be "unix" (or "unixgram" or
// "unixpacket") and the path to the socket should be given as the
// host parameter.
func JoinNetworkAddress(network, host, port string) string {
	var a string
	if network != "" {
		a = network + "/"
	}
	if (host != "" && port == "") || IsUnixNetwork(network) || IsFdNetwork(network) {
		a += host
	} else if port != "" {
		a += net.JoinHostPort(host, port)
	}
	return a
}

// ListenQUIC returns a http3.QUICEarlyListener suitable for use in a Caddy module.
//
// The network will be transformed into a QUIC-compatible type if the same address can be used with
// different networks. Currently this just means that for tcp, udp will be used with the same
// address instead.
//
// NOTE: This API is EXPERIMENTAL and may be changed or removed.
// NOTE: user should close the returned listener twice, once to stop accepting new connections, the second time to free up the packet conn.
func (na NetworkAddress) ListenQUIC(ctx context.Context, portOffset uint, config net.ListenConfig, tlsConf *tls.Config, pcWrappers []PacketConnWrapper) (http3.QUICListener, error) {
	lnKey := listenerKey("quic"+na.Network, na.JoinHostPort(portOffset))

	sharedEarlyListener, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) {
		lnAny, err := na.Listen(ctx, portOffset, config)
		if err != nil {
			return nil, err
		}

		ln := lnAny.(net.PacketConn)

		h3ln := ln
		if len(pcWrappers) == 0 {
			for {
				// retrieve the underlying socket, so quic-go can optimize.
				if unwrapper, ok := h3ln.(interface{ Unwrap() net.PacketConn }); ok {
					h3ln = unwrapper.Unwrap()
				} else {
					break
				}
			}
		} else {
			// wrap packet conn before QUIC
			for _, pcWrapper := range pcWrappers {
				h3ln = pcWrapper.WrapPacketConn(h3ln)
			}