@marcel91200 / caddy Mirror · read-only / commits / 7590c9ca
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 22:15 UTC

caddyhttp: Free up quic listener when stopping (#7177)

WeidiDeng committed Aug 14, 2025 at 02:35 UTC 7590c9ca1ba6096408574a7dd3b9dc42d12cb948
3 files changed +24 -1
listeners.go
+2
@@ -430,6 +430,7 @@ func JoinNetworkAddress(network, host, port string) string {
430 // address instead.
431 //
432 // NOTE: This API is EXPERIMENTAL and may be changed or removed.
433 +// NOTE: user should close the returned listener twice, once to stop accepting new connections, the second time to free up the packet conn.
434 func (na NetworkAddress) ListenQUIC(ctx context.Context, portOffset uint, config net.ListenConfig, tlsConf *tls.Config) (http3.QUICListener, error) {
435 lnKey := listenerKey("quic"+na.Network, na.JoinHostPort(portOffset))
436
@@ -626,6 +627,7 @@ func (fcql *fakeCloseQuicListener) Accept(_ context.Context) (*quic.Conn, error)
627 func (fcql *fakeCloseQuicListener) Close() error {
628 if atomic.CompareAndSwapInt32(&fcql.closed, 0, 1) {
629 fcql.contextCancel()
630 + } else if atomic.CompareAndSwapInt32(&fcql.closed, 1, 2) {
631 _, _ = listenerPool.Delete(fcql.sharedQuicListener.key)
632 }
633 return nil
modules/caddyhttp/app.go
+18
@@ -722,11 +722,29 @@ func (app *App) Stop() error {
722 return
723 }
724
725 + // closing quic listeners won't affect accepted connections now
726 + // so like stdlib, close listeners first, but keep the net.PacketConns open
727 + for _, h3ln := range server.quicListeners {
728 + if err := h3ln.Close(); err != nil {
729 + app.logger.Error("http3 listener close",
730 + zap.Error(err))
731 + }
732 + }
733 +
734 if err := server.h3server.Shutdown(ctx); err != nil {
735 app.logger.Error("HTTP/3 server shutdown",
736 zap.Error(err),
737 zap.Strings("addresses", server.Listen))
738 }
739 +
740 + // close the underlying net.PacketConns now
741 + // see the comment for ListenQUIC
742 + for _, h3ln := range server.quicListeners {
743 + if err := h3ln.Close(); err != nil {
744 + app.logger.Error("http3 listener close socket",
745 + zap.Error(err))
746 + }
747 + }
748 }
749 stopH2Listener := func(server *Server) {
750 defer finishedShutdown.Done()
modules/caddyhttp/server.go
+4 -1
@@ -235,7 +235,8 @@ type Server struct {
235 primaryHandlerChain Handler
236 errorHandlerChain Handler
237 listenerWrappers []caddy.ListenerWrapper
238 - listeners []net.Listener
238 + listeners []net.Listener // stdlib http.Server will close these
239 + quicListeners []http3.QUICListener // http3 now leave the quic.Listener management to us
240
241 tlsApp *caddytls.TLS
242 events *caddyevents.App
@@ -626,6 +627,8 @@ func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error
627 }
628 }
629
630 + s.quicListeners = append(s.quicListeners, h3ln)
631 +
632 //nolint:errcheck
633 go s.h3server.ServeListener(h3ln)
634