github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/testutil/testsyslog/testsyslog.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package testsyslog
    18  
    19  import (
    20  	"bufio"
    21  	"crypto/tls"
    22  	"io"
    23  	"log"
    24  	"net"
    25  	"os"
    26  	"runtime"
    27  	"time"
    28  
    29  	"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
    30  	"github.com/containerd/nerdctl/v2/pkg/testutil/testca"
    31  )
    32  
    33  func StartServer(n, la string, done chan<- string, certs ...*testca.Cert) (addr string, sock io.Closer) {
    34  	if n == "udp" || n == "tcp" || n == "tcp+tls" {
    35  		la = "127.0.0.1:0"
    36  	} else {
    37  		// unix and unixgram: choose an address if none given
    38  		if la == "" {
    39  			// use os.CreateTemp to get a name that is unique
    40  			f, err := os.CreateTemp("", "syslogtest")
    41  			if err != nil {
    42  				log.Fatal("TempFile: ", err)
    43  			}
    44  			f.Close()
    45  			la = f.Name()
    46  		}
    47  		os.Remove(la)
    48  	}
    49  
    50  	if n == "udp" || n == "unixgram" {
    51  		l, e := net.ListenPacket(n, la)
    52  		if e != nil {
    53  			log.Fatalf("startServer failed: %v", e)
    54  		}
    55  		addr = l.LocalAddr().String()
    56  		sock = l
    57  		go runPacketSyslog(l, done)
    58  	} else if n == "tcp+tls" {
    59  		if len(certs) == 0 {
    60  			log.Fatalf("certificates required.")
    61  		}
    62  		cer := certs[0]
    63  		if cer == nil {
    64  			log.Fatalf("certificates is nil")
    65  		}
    66  		cert, err := tls.LoadX509KeyPair(cer.CertPath, cer.KeyPath)
    67  		if err != nil {
    68  			log.Fatalf("failed to load TLS keypair: %v", err)
    69  		}
    70  		config := tls.Config{Certificates: []tls.Certificate{cert}}
    71  		l, e := tls.Listen("tcp", la, &config)
    72  		if e != nil {
    73  			log.Fatalf("startServer failed: %v", e)
    74  		}
    75  		addr = l.Addr().String()
    76  		sock = l
    77  		go runStreamSyslog(l, done)
    78  	} else {
    79  		l, e := net.Listen(n, la)
    80  		if e != nil {
    81  			log.Fatalf("startServer failed: %v", e)
    82  		}
    83  		addr = l.Addr().String()
    84  		sock = l
    85  		go runStreamSyslog(l, done)
    86  	}
    87  	return addr, sock
    88  }
    89  
    90  func TestableNetwork(network string) bool {
    91  	switch network {
    92  	case "unix", "unixgram":
    93  		switch runtime.GOOS {
    94  		case "darwin":
    95  			switch runtime.GOARCH {
    96  			case "arm", "arm64":
    97  				return false
    98  			}
    99  		case "windows":
   100  			return false
   101  		}
   102  	case "udp", "tcp", "tcp+tls":
   103  		return !rootlessutil.IsRootless()
   104  	}
   105  	return true
   106  }
   107  
   108  func runPacketSyslog(c net.PacketConn, done chan<- string) {
   109  	var buf [4096]byte
   110  	var rcvd string
   111  	ct := 0
   112  	for {
   113  		var n int
   114  		var err error
   115  
   116  		_ = c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
   117  		n, _, err = c.ReadFrom(buf[:])
   118  		rcvd += string(buf[:n])
   119  		if err != nil {
   120  			if oe, ok := err.(*net.OpError); ok {
   121  				if ct < 3 && oe.Temporary() {
   122  					ct++
   123  					continue
   124  				}
   125  			}
   126  			break
   127  		}
   128  	}
   129  	c.Close()
   130  	done <- rcvd
   131  }
   132  
   133  func runStreamSyslog(l net.Listener, done chan<- string) {
   134  	for {
   135  		var c net.Conn
   136  		var err error
   137  		if c, err = l.Accept(); err != nil {
   138  			return
   139  		}
   140  		go func(c net.Conn) {
   141  			_ = c.SetReadDeadline(time.Now().Add(5 * time.Second))
   142  			b := bufio.NewReader(c)
   143  			for ct := 1; ct&7 != 0; ct++ {
   144  				s, err := b.ReadString('\n')
   145  				if err != nil {
   146  					break
   147  				}
   148  				done <- s
   149  			}
   150  			c.Close()
   151  		}(c)
   152  	}
   153  }