123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- //go:build !js
- package net
- import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "sync"
- "testing"
- "time"
- )
- // testUnixAddr uses os.MkdirTemp to get a name that is unique.
- func testUnixAddr(t testing.TB) string {
- // Pass an empty pattern to get a directory name that is as short as possible.
- // If we end up with a name longer than the sun_path field in the sockaddr_un
- // struct, we won't be able to make the syscall to open the socket.
- d, err := os.MkdirTemp("", "")
- if err != nil {
- t.Fatal(err)
- }
- t.Cleanup(func() {
- if err := os.RemoveAll(d); err != nil {
- t.Error(err)
- }
- })
- return filepath.Join(d, "sock")
- }
- func newLocalListener(t testing.TB, network string) Listener {
- listen := func(net, addr string) Listener {
- ln, err := Listen(net, addr)
- if err != nil {
- t.Helper()
- t.Fatal(err)
- }
- return ln
- }
- switch network {
- case "tcp":
- if supportsIPv4() {
- if !supportsIPv6() {
- return listen("tcp4", "127.0.0.1:0")
- }
- if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil {
- return ln
- }
- }
- if supportsIPv6() {
- return listen("tcp6", "[::1]:0")
- }
- case "tcp4":
- if supportsIPv4() {
- return listen("tcp4", "127.0.0.1:0")
- }
- case "tcp6":
- if supportsIPv6() {
- return listen("tcp6", "[::1]:0")
- }
- case "unix", "unixpacket":
- return listen(network, testUnixAddr(t))
- }
- t.Helper()
- t.Fatalf("%s is not supported", network)
- return nil
- }
- func newDualStackListener() (lns []*TCPListener, err error) {
- var args = []struct {
- network string
- TCPAddr
- }{
- {"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}},
- {"tcp6", TCPAddr{IP: IPv6loopback}},
- }
- for i := 0; i < 64; i++ {
- var port int
- var lns []*TCPListener
- for _, arg := range args {
- arg.TCPAddr.Port = port
- ln, err := ListenTCP(arg.network, &arg.TCPAddr)
- if err != nil {
- continue
- }
- port = ln.Addr().(*TCPAddr).Port
- lns = append(lns, ln)
- }
- if len(lns) != len(args) {
- for _, ln := range lns {
- ln.Close()
- }
- continue
- }
- return lns, nil
- }
- return nil, errors.New("no dualstack port available")
- }
- type localServer struct {
- lnmu sync.RWMutex
- Listener
- done chan bool // signal that indicates server stopped
- cl []Conn // accepted connection list
- }
- func (ls *localServer) buildup(handler func(*localServer, Listener)) error {
- go func() {
- handler(ls, ls.Listener)
- close(ls.done)
- }()
- return nil
- }
- func (ls *localServer) teardown() error {
- ls.lnmu.Lock()
- defer ls.lnmu.Unlock()
- if ls.Listener != nil {
- network := ls.Listener.Addr().Network()
- address := ls.Listener.Addr().String()
- ls.Listener.Close()
- for _, c := range ls.cl {
- if err := c.Close(); err != nil {
- return err
- }
- }
- <-ls.done
- ls.Listener = nil
- switch network {
- case "unix", "unixpacket":
- os.Remove(address)
- }
- }
- return nil
- }
- func newLocalServer(t testing.TB, network string) *localServer {
- t.Helper()
- ln := newLocalListener(t, network)
- return &localServer{Listener: ln, done: make(chan bool)}
- }
- type streamListener struct {
- network, address string
- Listener
- done chan bool // signal that indicates server stopped
- }
- func (sl *streamListener) newLocalServer() *localServer {
- return &localServer{Listener: sl.Listener, done: make(chan bool)}
- }
- type dualStackServer struct {
- lnmu sync.RWMutex
- lns []streamListener
- port string
- cmu sync.RWMutex
- cs []Conn // established connections at the passive open side
- }
- func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error {
- for i := range dss.lns {
- go func(i int) {
- handler(dss, dss.lns[i].Listener)
- close(dss.lns[i].done)
- }(i)
- }
- return nil
- }
- func (dss *dualStackServer) teardownNetwork(network string) error {
- dss.lnmu.Lock()
- for i := range dss.lns {
- if network == dss.lns[i].network && dss.lns[i].Listener != nil {
- dss.lns[i].Listener.Close()
- <-dss.lns[i].done
- dss.lns[i].Listener = nil
- }
- }
- dss.lnmu.Unlock()
- return nil
- }
- func (dss *dualStackServer) teardown() error {
- dss.lnmu.Lock()
- for i := range dss.lns {
- if dss.lns[i].Listener != nil {
- dss.lns[i].Listener.Close()
- <-dss.lns[i].done
- }
- }
- dss.lns = dss.lns[:0]
- dss.lnmu.Unlock()
- dss.cmu.Lock()
- for _, c := range dss.cs {
- c.Close()
- }
- dss.cs = dss.cs[:0]
- dss.cmu.Unlock()
- return nil
- }
- func newDualStackServer() (*dualStackServer, error) {
- lns, err := newDualStackListener()
- if err != nil {
- return nil, err
- }
- _, port, err := SplitHostPort(lns[0].Addr().String())
- if err != nil {
- lns[0].Close()
- lns[1].Close()
- return nil, err
- }
- return &dualStackServer{
- lns: []streamListener{
- {network: "tcp4", address: lns[0].Addr().String(), Listener: lns[0], done: make(chan bool)},
- {network: "tcp6", address: lns[1].Addr().String(), Listener: lns[1], done: make(chan bool)},
- },
- port: port,
- }, nil
- }
- func (ls *localServer) transponder(ln Listener, ch chan<- error) {
- defer close(ch)
- switch ln := ln.(type) {
- case *TCPListener:
- ln.SetDeadline(time.Now().Add(someTimeout))
- case *UnixListener:
- ln.SetDeadline(time.Now().Add(someTimeout))
- }
- c, err := ln.Accept()
- if err != nil {
- if perr := parseAcceptError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- ls.cl = append(ls.cl, c)
- network := ln.Addr().Network()
- if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
- ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
- return
- }
- c.SetDeadline(time.Now().Add(someTimeout))
- c.SetReadDeadline(time.Now().Add(someTimeout))
- c.SetWriteDeadline(time.Now().Add(someTimeout))
- b := make([]byte, 256)
- n, err := c.Read(b)
- if err != nil {
- if perr := parseReadError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if _, err := c.Write(b[:n]); err != nil {
- if perr := parseWriteError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- }
- func transceiver(c Conn, wb []byte, ch chan<- error) {
- defer close(ch)
- c.SetDeadline(time.Now().Add(someTimeout))
- c.SetReadDeadline(time.Now().Add(someTimeout))
- c.SetWriteDeadline(time.Now().Add(someTimeout))
- n, err := c.Write(wb)
- if err != nil {
- if perr := parseWriteError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if n != len(wb) {
- ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
- }
- rb := make([]byte, len(wb))
- n, err = c.Read(rb)
- if err != nil {
- if perr := parseReadError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if n != len(wb) {
- ch <- fmt.Errorf("read %d; want %d", n, len(wb))
- }
- }
- func newLocalPacketListener(t testing.TB, network string) PacketConn {
- listenPacket := func(net, addr string) PacketConn {
- c, err := ListenPacket(net, addr)
- if err != nil {
- t.Helper()
- t.Fatal(err)
- }
- return c
- }
- switch network {
- case "udp":
- if supportsIPv4() {
- return listenPacket("udp4", "127.0.0.1:0")
- }
- if supportsIPv6() {
- return listenPacket("udp6", "[::1]:0")
- }
- case "udp4":
- if supportsIPv4() {
- return listenPacket("udp4", "127.0.0.1:0")
- }
- case "udp6":
- if supportsIPv6() {
- return listenPacket("udp6", "[::1]:0")
- }
- case "unixgram":
- return listenPacket(network, testUnixAddr(t))
- }
- t.Helper()
- t.Fatalf("%s is not supported", network)
- return nil
- }
- func newDualStackPacketListener() (cs []*UDPConn, err error) {
- var args = []struct {
- network string
- UDPAddr
- }{
- {"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}},
- {"udp6", UDPAddr{IP: IPv6loopback}},
- }
- for i := 0; i < 64; i++ {
- var port int
- var cs []*UDPConn
- for _, arg := range args {
- arg.UDPAddr.Port = port
- c, err := ListenUDP(arg.network, &arg.UDPAddr)
- if err != nil {
- continue
- }
- port = c.LocalAddr().(*UDPAddr).Port
- cs = append(cs, c)
- }
- if len(cs) != len(args) {
- for _, c := range cs {
- c.Close()
- }
- continue
- }
- return cs, nil
- }
- return nil, errors.New("no dualstack port available")
- }
- type localPacketServer struct {
- pcmu sync.RWMutex
- PacketConn
- done chan bool // signal that indicates server stopped
- }
- func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
- go func() {
- handler(ls, ls.PacketConn)
- close(ls.done)
- }()
- return nil
- }
- func (ls *localPacketServer) teardown() error {
- ls.pcmu.Lock()
- if ls.PacketConn != nil {
- network := ls.PacketConn.LocalAddr().Network()
- address := ls.PacketConn.LocalAddr().String()
- ls.PacketConn.Close()
- <-ls.done
- ls.PacketConn = nil
- switch network {
- case "unixgram":
- os.Remove(address)
- }
- }
- ls.pcmu.Unlock()
- return nil
- }
- func newLocalPacketServer(t testing.TB, network string) *localPacketServer {
- t.Helper()
- c := newLocalPacketListener(t, network)
- return &localPacketServer{PacketConn: c, done: make(chan bool)}
- }
- type packetListener struct {
- PacketConn
- }
- func (pl *packetListener) newLocalServer() *localPacketServer {
- return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}
- }
- func packetTransponder(c PacketConn, ch chan<- error) {
- defer close(ch)
- c.SetDeadline(time.Now().Add(someTimeout))
- c.SetReadDeadline(time.Now().Add(someTimeout))
- c.SetWriteDeadline(time.Now().Add(someTimeout))
- b := make([]byte, 256)
- n, peer, err := c.ReadFrom(b)
- if err != nil {
- if perr := parseReadError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if peer == nil { // for connected-mode sockets
- switch c.LocalAddr().Network() {
- case "udp":
- peer, err = ResolveUDPAddr("udp", string(b[:n]))
- case "unixgram":
- peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
- }
- if err != nil {
- ch <- err
- return
- }
- }
- if _, err := c.WriteTo(b[:n], peer); err != nil {
- if perr := parseWriteError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- }
- func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
- defer close(ch)
- c.SetDeadline(time.Now().Add(someTimeout))
- c.SetReadDeadline(time.Now().Add(someTimeout))
- c.SetWriteDeadline(time.Now().Add(someTimeout))
- n, err := c.WriteTo(wb, dst)
- if err != nil {
- if perr := parseWriteError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if n != len(wb) {
- ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
- }
- rb := make([]byte, len(wb))
- n, _, err = c.ReadFrom(rb)
- if err != nil {
- if perr := parseReadError(err); perr != nil {
- ch <- perr
- }
- ch <- err
- return
- }
- if n != len(wb) {
- ch <- fmt.Errorf("read %d; want %d", n, len(wb))
- }
- }
|