github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/net/mockserver_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !js 6 7 package net 8 9 import ( 10 "context" 11 "errors" 12 "fmt" 13 "os" 14 "path/filepath" 15 "sync" 16 "testing" 17 "time" 18 ) 19 20 // testUnixAddr uses os.MkdirTemp to get a name that is unique. 21 func testUnixAddr(t testing.TB) string { 22 // Pass an empty pattern to get a directory name that is as short as possible. 23 // If we end up with a name longer than the sun_path field in the sockaddr_un 24 // struct, we won't be able to make the syscall to open the socket. 25 d, err := os.MkdirTemp("", "") 26 if err != nil { 27 t.Fatal(err) 28 } 29 t.Cleanup(func() { 30 if err := os.RemoveAll(d); err != nil { 31 t.Error(err) 32 } 33 }) 34 return filepath.Join(d, "sock") 35 } 36 37 func newLocalListener(t testing.TB, network string, lcOpt ...*ListenConfig) Listener { 38 var lc *ListenConfig 39 switch len(lcOpt) { 40 case 0: 41 lc = new(ListenConfig) 42 case 1: 43 lc = lcOpt[0] 44 default: 45 t.Helper() 46 t.Fatal("too many ListenConfigs passed to newLocalListener: want 0 or 1") 47 } 48 49 listen := func(net, addr string) Listener { 50 ln, err := lc.Listen(context.Background(), net, addr) 51 if err != nil { 52 t.Helper() 53 t.Fatal(err) 54 } 55 return ln 56 } 57 58 switch network { 59 case "tcp": 60 if supportsIPv4() { 61 if !supportsIPv6() { 62 return listen("tcp4", "127.0.0.1:0") 63 } 64 if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil { 65 return ln 66 } 67 } 68 if supportsIPv6() { 69 return listen("tcp6", "[::1]:0") 70 } 71 case "tcp4": 72 if supportsIPv4() { 73 return listen("tcp4", "127.0.0.1:0") 74 } 75 case "tcp6": 76 if supportsIPv6() { 77 return listen("tcp6", "[::1]:0") 78 } 79 case "unix", "unixpacket": 80 return listen(network, testUnixAddr(t)) 81 } 82 83 t.Helper() 84 t.Fatalf("%s is not supported", network) 85 return nil 86 } 87 88 func newDualStackListener() (lns []*TCPListener, err error) { 89 var args = []struct { 90 network string 91 TCPAddr 92 }{ 93 {"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}}, 94 {"tcp6", TCPAddr{IP: IPv6loopback}}, 95 } 96 for i := 0; i < 64; i++ { 97 var port int 98 var lns []*TCPListener 99 for _, arg := range args { 100 arg.TCPAddr.Port = port 101 ln, err := ListenTCP(arg.network, &arg.TCPAddr) 102 if err != nil { 103 continue 104 } 105 port = ln.Addr().(*TCPAddr).Port 106 lns = append(lns, ln) 107 } 108 if len(lns) != len(args) { 109 for _, ln := range lns { 110 ln.Close() 111 } 112 continue 113 } 114 return lns, nil 115 } 116 return nil, errors.New("no dualstack port available") 117 } 118 119 type localServer struct { 120 lnmu sync.RWMutex 121 Listener 122 done chan bool // signal that indicates server stopped 123 cl []Conn // accepted connection list 124 } 125 126 func (ls *localServer) buildup(handler func(*localServer, Listener)) error { 127 go func() { 128 handler(ls, ls.Listener) 129 close(ls.done) 130 }() 131 return nil 132 } 133 134 func (ls *localServer) teardown() error { 135 ls.lnmu.Lock() 136 defer ls.lnmu.Unlock() 137 if ls.Listener != nil { 138 network := ls.Listener.Addr().Network() 139 address := ls.Listener.Addr().String() 140 ls.Listener.Close() 141 for _, c := range ls.cl { 142 if err := c.Close(); err != nil { 143 return err 144 } 145 } 146 <-ls.done 147 ls.Listener = nil 148 switch network { 149 case "unix", "unixpacket": 150 os.Remove(address) 151 } 152 } 153 return nil 154 } 155 156 func newLocalServer(t testing.TB, network string) *localServer { 157 t.Helper() 158 ln := newLocalListener(t, network) 159 return &localServer{Listener: ln, done: make(chan bool)} 160 } 161 162 type streamListener struct { 163 network, address string 164 Listener 165 done chan bool // signal that indicates server stopped 166 } 167 168 func (sl *streamListener) newLocalServer() *localServer { 169 return &localServer{Listener: sl.Listener, done: make(chan bool)} 170 } 171 172 type dualStackServer struct { 173 lnmu sync.RWMutex 174 lns []streamListener 175 port string 176 177 cmu sync.RWMutex 178 cs []Conn // established connections at the passive open side 179 } 180 181 func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error { 182 for i := range dss.lns { 183 go func(i int) { 184 handler(dss, dss.lns[i].Listener) 185 close(dss.lns[i].done) 186 }(i) 187 } 188 return nil 189 } 190 191 func (dss *dualStackServer) teardownNetwork(network string) error { 192 dss.lnmu.Lock() 193 for i := range dss.lns { 194 if network == dss.lns[i].network && dss.lns[i].Listener != nil { 195 dss.lns[i].Listener.Close() 196 <-dss.lns[i].done 197 dss.lns[i].Listener = nil 198 } 199 } 200 dss.lnmu.Unlock() 201 return nil 202 } 203 204 func (dss *dualStackServer) teardown() error { 205 dss.lnmu.Lock() 206 for i := range dss.lns { 207 if dss.lns[i].Listener != nil { 208 dss.lns[i].Listener.Close() 209 <-dss.lns[i].done 210 } 211 } 212 dss.lns = dss.lns[:0] 213 dss.lnmu.Unlock() 214 dss.cmu.Lock() 215 for _, c := range dss.cs { 216 c.Close() 217 } 218 dss.cs = dss.cs[:0] 219 dss.cmu.Unlock() 220 return nil 221 } 222 223 func newDualStackServer() (*dualStackServer, error) { 224 lns, err := newDualStackListener() 225 if err != nil { 226 return nil, err 227 } 228 _, port, err := SplitHostPort(lns[0].Addr().String()) 229 if err != nil { 230 lns[0].Close() 231 lns[1].Close() 232 return nil, err 233 } 234 return &dualStackServer{ 235 lns: []streamListener{ 236 {network: "tcp4", address: lns[0].Addr().String(), Listener: lns[0], done: make(chan bool)}, 237 {network: "tcp6", address: lns[1].Addr().String(), Listener: lns[1], done: make(chan bool)}, 238 }, 239 port: port, 240 }, nil 241 } 242 243 func (ls *localServer) transponder(ln Listener, ch chan<- error) { 244 defer close(ch) 245 246 switch ln := ln.(type) { 247 case *TCPListener: 248 ln.SetDeadline(time.Now().Add(someTimeout)) 249 case *UnixListener: 250 ln.SetDeadline(time.Now().Add(someTimeout)) 251 } 252 c, err := ln.Accept() 253 if err != nil { 254 if perr := parseAcceptError(err); perr != nil { 255 ch <- perr 256 } 257 ch <- err 258 return 259 } 260 ls.cl = append(ls.cl, c) 261 262 network := ln.Addr().Network() 263 if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network { 264 ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) 265 return 266 } 267 c.SetDeadline(time.Now().Add(someTimeout)) 268 c.SetReadDeadline(time.Now().Add(someTimeout)) 269 c.SetWriteDeadline(time.Now().Add(someTimeout)) 270 271 b := make([]byte, 256) 272 n, err := c.Read(b) 273 if err != nil { 274 if perr := parseReadError(err); perr != nil { 275 ch <- perr 276 } 277 ch <- err 278 return 279 } 280 if _, err := c.Write(b[:n]); err != nil { 281 if perr := parseWriteError(err); perr != nil { 282 ch <- perr 283 } 284 ch <- err 285 return 286 } 287 } 288 289 func transceiver(c Conn, wb []byte, ch chan<- error) { 290 defer close(ch) 291 292 c.SetDeadline(time.Now().Add(someTimeout)) 293 c.SetReadDeadline(time.Now().Add(someTimeout)) 294 c.SetWriteDeadline(time.Now().Add(someTimeout)) 295 296 n, err := c.Write(wb) 297 if err != nil { 298 if perr := parseWriteError(err); perr != nil { 299 ch <- perr 300 } 301 ch <- err 302 return 303 } 304 if n != len(wb) { 305 ch <- fmt.Errorf("wrote %d; want %d", n, len(wb)) 306 } 307 rb := make([]byte, len(wb)) 308 n, err = c.Read(rb) 309 if err != nil { 310 if perr := parseReadError(err); perr != nil { 311 ch <- perr 312 } 313 ch <- err 314 return 315 } 316 if n != len(wb) { 317 ch <- fmt.Errorf("read %d; want %d", n, len(wb)) 318 } 319 } 320 321 func newLocalPacketListener(t testing.TB, network string, lcOpt ...*ListenConfig) PacketConn { 322 var lc *ListenConfig 323 switch len(lcOpt) { 324 case 0: 325 lc = new(ListenConfig) 326 case 1: 327 lc = lcOpt[0] 328 default: 329 t.Helper() 330 t.Fatal("too many ListenConfigs passed to newLocalListener: want 0 or 1") 331 } 332 333 listenPacket := func(net, addr string) PacketConn { 334 c, err := lc.ListenPacket(context.Background(), net, addr) 335 if err != nil { 336 t.Helper() 337 t.Fatal(err) 338 } 339 return c 340 } 341 342 switch network { 343 case "udp": 344 if supportsIPv4() { 345 return listenPacket("udp4", "127.0.0.1:0") 346 } 347 if supportsIPv6() { 348 return listenPacket("udp6", "[::1]:0") 349 } 350 case "udp4": 351 if supportsIPv4() { 352 return listenPacket("udp4", "127.0.0.1:0") 353 } 354 case "udp6": 355 if supportsIPv6() { 356 return listenPacket("udp6", "[::1]:0") 357 } 358 case "unixgram": 359 return listenPacket(network, testUnixAddr(t)) 360 } 361 362 t.Helper() 363 t.Fatalf("%s is not supported", network) 364 return nil 365 } 366 367 func newDualStackPacketListener() (cs []*UDPConn, err error) { 368 var args = []struct { 369 network string 370 UDPAddr 371 }{ 372 {"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}}, 373 {"udp6", UDPAddr{IP: IPv6loopback}}, 374 } 375 for i := 0; i < 64; i++ { 376 var port int 377 var cs []*UDPConn 378 for _, arg := range args { 379 arg.UDPAddr.Port = port 380 c, err := ListenUDP(arg.network, &arg.UDPAddr) 381 if err != nil { 382 continue 383 } 384 port = c.LocalAddr().(*UDPAddr).Port 385 cs = append(cs, c) 386 } 387 if len(cs) != len(args) { 388 for _, c := range cs { 389 c.Close() 390 } 391 continue 392 } 393 return cs, nil 394 } 395 return nil, errors.New("no dualstack port available") 396 } 397 398 type localPacketServer struct { 399 pcmu sync.RWMutex 400 PacketConn 401 done chan bool // signal that indicates server stopped 402 } 403 404 func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error { 405 go func() { 406 handler(ls, ls.PacketConn) 407 close(ls.done) 408 }() 409 return nil 410 } 411 412 func (ls *localPacketServer) teardown() error { 413 ls.pcmu.Lock() 414 if ls.PacketConn != nil { 415 network := ls.PacketConn.LocalAddr().Network() 416 address := ls.PacketConn.LocalAddr().String() 417 ls.PacketConn.Close() 418 <-ls.done 419 ls.PacketConn = nil 420 switch network { 421 case "unixgram": 422 os.Remove(address) 423 } 424 } 425 ls.pcmu.Unlock() 426 return nil 427 } 428 429 func newLocalPacketServer(t testing.TB, network string) *localPacketServer { 430 t.Helper() 431 c := newLocalPacketListener(t, network) 432 return &localPacketServer{PacketConn: c, done: make(chan bool)} 433 } 434 435 type packetListener struct { 436 PacketConn 437 } 438 439 func (pl *packetListener) newLocalServer() *localPacketServer { 440 return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)} 441 } 442 443 func packetTransponder(c PacketConn, ch chan<- error) { 444 defer close(ch) 445 446 c.SetDeadline(time.Now().Add(someTimeout)) 447 c.SetReadDeadline(time.Now().Add(someTimeout)) 448 c.SetWriteDeadline(time.Now().Add(someTimeout)) 449 450 b := make([]byte, 256) 451 n, peer, err := c.ReadFrom(b) 452 if err != nil { 453 if perr := parseReadError(err); perr != nil { 454 ch <- perr 455 } 456 ch <- err 457 return 458 } 459 if peer == nil { // for connected-mode sockets 460 switch c.LocalAddr().Network() { 461 case "udp": 462 peer, err = ResolveUDPAddr("udp", string(b[:n])) 463 case "unixgram": 464 peer, err = ResolveUnixAddr("unixgram", string(b[:n])) 465 } 466 if err != nil { 467 ch <- err 468 return 469 } 470 } 471 if _, err := c.WriteTo(b[:n], peer); err != nil { 472 if perr := parseWriteError(err); perr != nil { 473 ch <- perr 474 } 475 ch <- err 476 return 477 } 478 } 479 480 func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) { 481 defer close(ch) 482 483 c.SetDeadline(time.Now().Add(someTimeout)) 484 c.SetReadDeadline(time.Now().Add(someTimeout)) 485 c.SetWriteDeadline(time.Now().Add(someTimeout)) 486 487 n, err := c.WriteTo(wb, dst) 488 if err != nil { 489 if perr := parseWriteError(err); perr != nil { 490 ch <- perr 491 } 492 ch <- err 493 return 494 } 495 if n != len(wb) { 496 ch <- fmt.Errorf("wrote %d; want %d", n, len(wb)) 497 } 498 rb := make([]byte, len(wb)) 499 n, _, err = c.ReadFrom(rb) 500 if err != nil { 501 if perr := parseReadError(err); perr != nil { 502 ch <- perr 503 } 504 ch <- err 505 return 506 } 507 if n != len(wb) { 508 ch <- fmt.Errorf("read %d; want %d", n, len(wb)) 509 } 510 }