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 }