// 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. package net import ( "fmt" "os" "sync" ) func newLocalListener(network string) (Listener, error) { switch network { case "tcp", "tcp4", "tcp6": if supportsIPv4 { return Listen("tcp4", "127.0.0.1:0") } if supportsIPv6 { return Listen("tcp6", "[::1]:0") } case "unix", "unixpacket": return Listen(network, testUnixAddr()) } return nil, fmt.Errorf("%s is not supported", network) } type localServer struct { lnmu sync.RWMutex Listener done chan bool // signal that indicates server stopped } 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() if ls.Listener != nil { network := ls.Listener.Addr().Network() address := ls.Listener.Addr().String() ls.Listener.Close() <-ls.done ls.Listener = nil switch network { case "unix", "unixpacket": os.Remove(address) } } ls.lnmu.Unlock() return nil } func newLocalServer(network string) (*localServer, error) { ln, err := newLocalListener(network) if err != nil { return nil, err } return &localServer{Listener: ln, done: make(chan bool)}, nil } type streamListener struct { network, address string Listener done chan bool // signal that indicates server stopped } func (sl *streamListener) newLocalServer() (*localServer, error) { return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil } 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) putConn(c Conn) error { dss.cmu.Lock() dss.cs = append(dss.cs, c) dss.cmu.Unlock() 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(lns []streamListener) (*dualStackServer, error) { dss := &dualStackServer{lns: lns, port: "0"} for i := range dss.lns { ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port)) if err != nil { for _, ln := range dss.lns { ln.Listener.Close() } return nil, err } dss.lns[i].Listener = ln dss.lns[i].done = make(chan bool) if dss.port == "0" { if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil { for _, ln := range dss.lns { ln.Listener.Close() } return nil, err } } } return dss, nil }