blob: 3a21452f714342ab4332105a2ecbdec44f464cc9 [file] [log] [blame]
// 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
}