// Dial the given address and return a point to point connection. // The connection is secured if tlscfg is not nil. // Using MuxDial is preferred because muxes provide flow control. func Dial(addr string, tlscfg ...*tls.Config) (c ch.Conn, err error) { var cfg *tls.Config if len(tlscfg) > 0 { cfg = tlscfg[0] } if nc, err := dial(addr, cfg); err == nil { c = ch.NewConn(nc, 0, nil) c.Tag = addr return c, nil } return c, err }
func serveLoop(l net.Listener, rc chan ch.Conn, ec chan bool, addr, tag string, tlscfg *tls.Config) { if strings.HasPrefix(addr, "/tmp/") { defer os.Remove(addr) } closes := map[io.Closer]bool{} var closeslk sync.Mutex go func() { <-ec l.Close() closeslk.Lock() for c := range closes { c.Close() } closeslk.Unlock() }() var err error ncli := 0 for { fd, e := l.Accept() if e != nil { err = e break } closeslk.Lock() var cfd io.Closer = fd closes[cfd] = true closeslk.Unlock() raddr := fd.RemoteAddr().String() if raddr == "" { // unix sockets do not provide raddr raddr = fmt.Sprintf("local!%d", ncli) ncli++ } else { if n := strings.LastIndex(raddr, ":"); n > 0 { raddr = raddr[:n] + "!" + raddr[n+1:] } } if tlscfg != nil { if c, ok := fd.(*net.TCPConn); ok { c.SetKeepAlivePeriod(30 * time.Second) c.SetKeepAlive(true) } fd = tls.Server(fd, tlscfg) } cn := ch.NewConn(fd, 0, nil) cn.Tag = raddr if ok := rc <- cn; !ok { err = cerror(rc) break } } close(rc, err) close(ec, err) } func serve1(nw, host, port string, tlscfg *tls.Config) (c <-chan ch.Conn, ec chan bool, err error) { tag := fmt.Sprintf("%s!%s!%s", nw, host, port) if nw == "tls" { nw = "tcp" if tlscfg == nil { tlscfg = ServerTLSCfg if tlscfg == nil { return nil, nil, ErrNoTLSCfg } } } if nw == "tcp" && (host == "local" || host == "*" || host == "localhost") { host = "" } addr := host + ":" + port if nw == "unix" { addr = port tlscfg = nil os.Remove(port) } dbg.Warn("listen at %s (%s:%s)", tag, nw, addr) fd, err := net.Listen(nw, addr) if err != nil { return nil, nil, err } rc := make(chan ch.Conn) rec := make(chan bool) go serveLoop(fd, rc, rec, addr, tag, tlscfg) return rc, rec, nil } func serveBoth(c1 <-chan ch.Conn, ec1 chan<- bool, c2 <-chan ch.Conn, ec2 chan bool) (c <-chan ch.Conn, ec chan bool, err error) { xc := make(chan ch.Conn) xec := make(chan bool) go func() { var err error doselect { case cn, ok := <-c1: if !ok { err = cerror(c1) if c2 == nil { break } c1 = nil } if ok = xc <- cn; !ok { err = cerror(xc) break } case cn, ok := <-c2: err = cerror(c2) if !ok { if c1 == nil { break } c2 = nil } if ok = xc <- cn; !ok { err = cerror(xc) break } case <-xec: err = cerror(xec) break } close(ec1, err) close(ec2, err) close(c1, err) close(c2, err) close(xec, err) close(xc, err) }() return xc, xec, nil }