| // 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 "sync" |
| |
| type streamListener struct { |
| net, addr string |
| ln Listener |
| } |
| |
| 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(server func(*dualStackServer, Listener)) error { |
| for i := range dss.lns { |
| go server(dss, dss.lns[i].ln) |
| } |
| 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(net string) error { |
| dss.lnmu.Lock() |
| for i := range dss.lns { |
| if net == dss.lns[i].net && dss.lns[i].ln != nil { |
| dss.lns[i].ln.Close() |
| dss.lns[i].ln = nil |
| } |
| } |
| dss.lnmu.Unlock() |
| return nil |
| } |
| |
| func (dss *dualStackServer) teardown() error { |
| dss.lnmu.Lock() |
| for i := range dss.lns { |
| if dss.lns[i].ln != nil { |
| dss.lns[i].ln.Close() |
| } |
| } |
| dss.lnmu.Unlock() |
| dss.cmu.Lock() |
| for _, c := range dss.cs { |
| c.Close() |
| } |
| 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].net, dss.lns[i].addr+":"+dss.port) |
| if err != nil { |
| dss.teardown() |
| return nil, err |
| } |
| dss.lns[i].ln = ln |
| if dss.port == "0" { |
| if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil { |
| dss.teardown() |
| return nil, err |
| } |
| } |
| } |
| return dss, nil |
| } |