func (a *App) Start() error {
	for _, s := range a.Servers {
		for _, addr := range s.listenAddrs {
			for i := uint(0); i < addr.PortRangeSize(); i++ {
				var lnAddr string
				if strings.Contains(addr.Network, "udp") {
					pc, err := caddy.ListenPacket(addr.Network, addr.JoinHostPort(i))
					if err != nil {
						return err
					}
					a.packetConns = append(a.packetConns, pc)
					lnAddr = pc.LocalAddr().Network() + "/" + pc.LocalAddr().String()
					go s.servePacket(pc)
				} else {
					ln, err := caddy.Listen(addr.Network, addr.JoinHostPort(i))
					if err != nil {
						return err
					}
					a.listeners = append(a.listeners, ln)
					lnAddr = ln.Addr().Network() + "/" + ln.Addr().String()
					go s.serve(ln)
				}
				s.logger.Debug("listening", zap.String("address", lnAddr))
			}
		}
	}
	return nil
}
Start starts the app.
package layer4
import (
	"fmt"
	"net"
	"strings"
	"github.com/caddyserver/caddy/v2"
	"go.uber.org/zap"
)
func init() {
	caddy.RegisterModule(App{})
}
type App struct {
	Servers map[string]*Server `json:"servers,omitempty"`
	listeners   []net.Listener
	packetConns []net.PacketConn
	logger      *zap.Logger
}
func (App) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "layer4",
		New: func() caddy.Module { return new(App) },
	}
}
func (a *App) Provision(ctx caddy.Context) error {
	a.logger = ctx.Logger(a)
	for srvName, srv := range a.Servers {
		err := srv.Provision(ctx, a.logger)
		if err != nil {
			return fmt.Errorf("server '%s': %v", srvName, err)
		}
	}
	return nil
}