github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/layer4/app.go (about)

     1  // Copyright 2020 Matthew Holt
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package layer4
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/caddyserver/caddy/v2"
    22  	"go.uber.org/zap"
    23  )
    24  
    25  func init() {
    26  	caddy.RegisterModule(&App{})
    27  }
    28  
    29  // App is a Caddy app that operates closest to layer 4 of the OSI model.
    30  type App struct {
    31  	// Servers are the servers to create. The key of each server must be
    32  	// a unique name identifying the server for your own convenience;
    33  	// the order of servers does not matter.
    34  	Servers map[string]*Server `json:"servers,omitempty"`
    35  
    36  	listeners   []net.Listener
    37  	packetConns []net.PacketConn
    38  	logger      *zap.Logger
    39  	ctx         caddy.Context
    40  }
    41  
    42  // CaddyModule returns the Caddy module information.
    43  func (*App) CaddyModule() caddy.ModuleInfo {
    44  	return caddy.ModuleInfo{
    45  		ID:  "layer4",
    46  		New: func() caddy.Module { return new(App) },
    47  	}
    48  }
    49  
    50  // Provision sets up the app.
    51  func (a *App) Provision(ctx caddy.Context) error {
    52  	a.ctx = ctx
    53  	a.logger = ctx.Logger()
    54  
    55  	for srvName, srv := range a.Servers {
    56  		err := srv.Provision(ctx, a.logger)
    57  		if err != nil {
    58  			return fmt.Errorf("server '%s': %v", srvName, err)
    59  		}
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  // Start starts the app.
    66  func (a *App) Start() error {
    67  	for _, s := range a.Servers {
    68  		for _, addr := range s.listenAddrs {
    69  			listeners, err := addr.ListenAll(a.ctx, net.ListenConfig{})
    70  			if err != nil {
    71  				return err
    72  			}
    73  			for _, lnAny := range listeners {
    74  				var lnAddr string
    75  				switch ln := lnAny.(type) {
    76  				case net.Listener:
    77  					a.listeners = append(a.listeners, ln)
    78  					lnAddr = caddy.JoinNetworkAddress(ln.Addr().Network(), ln.Addr().String(), "")
    79  					go func(s *Server, ln net.Listener) {
    80  						_ = s.serve(ln)
    81  					}(s, ln)
    82  				case net.PacketConn:
    83  					a.packetConns = append(a.packetConns, ln)
    84  					lnAddr = caddy.JoinNetworkAddress(ln.LocalAddr().Network(), ln.LocalAddr().String(), "")
    85  					go func(s *Server, pc net.PacketConn) {
    86  						_ = s.servePacket(pc)
    87  					}(s, ln)
    88  				}
    89  				s.logger.Debug("listening", zap.String("address", lnAddr))
    90  			}
    91  		}
    92  	}
    93  	return nil
    94  }
    95  
    96  // Stop stops the servers and closes all listeners.
    97  func (a *App) Stop() error {
    98  	for _, pc := range a.packetConns {
    99  		err := pc.Close()
   100  		if err != nil {
   101  			a.logger.Error("closing packet listener",
   102  				zap.String("network", pc.LocalAddr().Network()),
   103  				zap.String("address", pc.LocalAddr().String()),
   104  				zap.Error(err))
   105  		}
   106  	}
   107  	for _, ln := range a.listeners {
   108  		err := ln.Close()
   109  		if err != nil {
   110  			a.logger.Error("closing listener",
   111  				zap.String("network", ln.Addr().Network()),
   112  				zap.String("address", ln.Addr().String()),
   113  				zap.Error(err))
   114  		}
   115  	}
   116  	return nil
   117  }
   118  
   119  // Interface guard
   120  var _ caddy.App = (*App)(nil)