func Open(info *Info, opts DialOpts) (*State, error) { // TODO Select a random address from info.Addrs // and only fail when we've tried all the addresses. // TODO what does "origin" really mean, and is localhost always ok? cfg, err := websocket.NewConfig("wss://"+info.Addrs[0]+"/", "http://localhost/") if err != nil { return nil, err } pool := x509.NewCertPool() xcert, err := cert.ParseCert(info.CACert) if err != nil { return nil, err } pool.AddCert(xcert) cfg.TlsConfig = &tls.Config{ RootCAs: pool, ServerName: "anything", } var conn *websocket.Conn openAttempt := utils.AttemptStrategy{ Total: opts.Timeout, Delay: opts.RetryDelay, } for a := openAttempt.Start(); a.Next(); { log.Infof("state/api: dialing %q", cfg.Location) conn, err = websocket.DialConfig(cfg) if err == nil { break } log.Errorf("state/api: %v", err) } if err != nil { return nil, err } log.Infof("state/api: connection established") client := rpc.NewConn(jsoncodec.NewWebsocket(conn)) client.Start() st := &State{ client: client, conn: conn, } 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 *C, root interface{}, tfErr func(error) error, bidir bool) (*rpc.Conn, <-chan error) { l, err := net.Listen("tcp", "127.0.0.1:0") c.Assert(err, IsNil) srvDone := make(chan error, 1) go func() { conn, err := l.Accept() if err != nil { srvDone <- err return } defer l.Close() role := roleServer if bidir { role = roleBoth } rpcConn := rpc.NewConn(NewJSONCodec(conn, role)) err = rpcConn.Serve(root, tfErr) if err != nil { srvDone <- err return } 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, IsNil) role := roleClient if bidir { role = roleBoth } client := rpc.NewConn(NewJSONCodec(conn, role)) client.Start() return client, srvDone }
func (srv *Server) serveConn(wsConn *websocket.Conn) error { codec := jsoncodec.NewWebsocket(wsConn) if loggo.GetLogger("").EffectiveLogLevel() >= loggo.DEBUG { codec.SetLogging(true) } conn := rpc.NewConn(codec) if err := conn.Serve(newStateServer(srv, conn), serverError); err != nil { return err } conn.Start() select { case <-conn.Dead(): case <-srv.tomb.Dying(): } return conn.Close() }