예제 #1
0
파일: net.go 프로젝트: chengguozhen/clive
// 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
}
예제 #2
0
파일: net.go 프로젝트: chengguozhen/clive
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
}