func Open(info *Info, opts DialOpts) (*State, error) { if len(info.Addrs) == 0 { return nil, fmt.Errorf("no API addresses to connect to") } pool := x509.NewCertPool() xcert, err := cert.ParseCert(info.CACert) if err != nil { return nil, err } pool.AddCert(xcert) // Dial all addresses at reasonable intervals. try := parallel.NewTry(0, nil) defer try.Kill() for _, addr := range info.Addrs { err := dialWebsocket(addr, opts, pool, try) if err == parallel.ErrStopped { break } if err != nil { return nil, err } select { case <-time.After(opts.DialAddressInterval): case <-try.Dead(): } } try.Close() result, err := try.Result() if err != nil { return nil, err } conn := result.(*websocket.Conn) logger.Infof("connection established to %q", conn.RemoteAddr()) client := rpc.NewConn(jsoncodec.NewWebsocket(conn), nil) client.Start() st := &State{ client: client, conn: conn, addr: conn.Config().Location.Host, serverRoot: "https://" + conn.Config().Location.Host, tag: info.Tag, password: info.Password, certPool: pool, } if info.Tag != "" || info.Password != "" { if err := st.Login(info.Tag, info.Password, info.Nonce); err != nil { conn.Close() return nil, err } } st.broken = make(chan struct{}) go st.heartbeatMonitor() return st, nil }
// newRPCClientServer starts an RPC server serving a connection from a // single client. When the server has finished serving the connection, // it sends a value on the returned channel. // If bidir is true, requests can flow in both directions. func newRPCClientServer(c *gc.C, root interface{}, tfErr func(error) error, bidir bool) (client *rpc.Conn, srvDone chan error, clientNotifier, serverNotifier *notifier) { l, err := net.Listen("tcp", "127.0.0.1:0") c.Assert(err, gc.IsNil) srvDone = make(chan error, 1) clientNotifier = new(notifier) serverNotifier = new(notifier) go func() { conn, err := l.Accept() if err != nil { srvDone <- nil return } defer l.Close() role := roleServer if bidir { role = roleBoth } rpcConn := rpc.NewConn(NewJSONCodec(conn, role), serverNotifier) rpcConn.Serve(root, tfErr) if root, ok := root.(*Root); ok { root.conn = rpcConn } rpcConn.Start() <-rpcConn.Dead() srvDone <- rpcConn.Close() }() conn, err := net.Dial("tcp", l.Addr().String()) c.Assert(err, gc.IsNil) role := roleClient if bidir { role = roleBoth } client = rpc.NewConn(NewJSONCodec(conn, role), clientNotifier) client.Start() return client, srvDone, clientNotifier, serverNotifier }
func (srv *Server) serveConn(wsConn *websocket.Conn, reqNotifier *requestNotifier) error { codec := jsoncodec.NewWebsocket(wsConn) if loggo.GetLogger("juju.rpc.jsoncodec").EffectiveLogLevel() <= loggo.TRACE { codec.SetLogging(true) } var notifier rpc.RequestNotifier if logger.EffectiveLogLevel() <= loggo.DEBUG { // Incur request monitoring overhead only if we // know we'll need it. notifier = reqNotifier } conn := rpc.NewConn(codec, notifier) conn.Serve(newStateServer(srv, conn, reqNotifier, srv.limiter), serverError) conn.Start() select { case <-conn.Dead(): case <-srv.tomb.Dying(): } return conn.Close() }