services/identity: Switch identityd to use xrpc server.

Change-Id: Ifbdedfa9a89e2784109edcd0d1c80ae902135ed4
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index 480573a..3e05bef 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -122,7 +122,6 @@
 		return fmt.Errorf("Failed to start RevocationManager: %v", err)
 	}
 
-	listenSpec := v23.GetListenSpec(ctx)
 	s := server.NewIdentityServer(
 		googleoauth,
 		auditor,
@@ -132,7 +131,7 @@
 		caveats.NewBrowserCaveatSelector(assetsPrefix),
 		assetsPrefix,
 		mountPrefix)
-	s.Serve(ctx, &listenSpec, externalHttpAddr, httpAddr, tlsConfig)
+	s.Serve(ctx, externalHttpAddr, httpAddr, tlsConfig)
 	return nil
 }
 
diff --git a/services/identity/identitylib/test_identityd.go b/services/identity/identitylib/test_identityd.go
index 1038239..b8e6bf1 100644
--- a/services/identity/identitylib/test_identityd.go
+++ b/services/identity/identitylib/test_identityd.go
@@ -97,9 +97,7 @@
 		"",
 		"identity")
 
-	l := v23.GetListenSpec(ctx)
-
-	_, eps, externalHttpAddress := s.Listen(ctx, &l, *externalHttpAddr, *httpAddr, *tlsConfig)
+	_, eps, externalHttpAddress := s.Listen(ctx, *externalHttpAddr, *httpAddr, *tlsConfig)
 
 	fmt.Fprintf(env.Stdout, "TEST_IDENTITYD_NAME=%s\n", eps[0])
 	fmt.Fprintf(env.Stdout, "TEST_IDENTITYD_HTTP_ADDR=%s\n", externalHttpAddress)
diff --git a/services/identity/internal/identityd_test/main.go b/services/identity/internal/identityd_test/main.go
index 3b3b152..d014291 100644
--- a/services/identity/internal/identityd_test/main.go
+++ b/services/identity/internal/identityd_test/main.go
@@ -12,7 +12,6 @@
 	"net"
 	"time"
 
-	"v.io/v23"
 	"v.io/v23/context"
 	"v.io/x/lib/cmdline"
 	"v.io/x/ref/lib/v23cmd"
@@ -114,7 +113,6 @@
 		caveatSelector = caveats.NewBrowserCaveatSelector(assetsPrefix)
 	}
 
-	listenSpec := v23.GetListenSpec(ctx)
 	s := server.NewIdentityServer(
 		oauthProvider,
 		auditor,
@@ -124,6 +122,6 @@
 		caveatSelector,
 		assetsPrefix,
 		mountPrefix)
-	s.Serve(ctx, &listenSpec, externalHttpAddr, httpAddr, tlsConfig)
+	s.Serve(ctx, externalHttpAddr, httpAddr, tlsConfig)
 	return nil
 }
diff --git a/services/identity/internal/server/identityd.go b/services/identity/internal/server/identityd.go
index a14a6ba..4677015 100644
--- a/services/identity/internal/server/identityd.go
+++ b/services/identity/internal/server/identityd.go
@@ -14,6 +14,7 @@
 	"reflect"
 	"strconv"
 	"strings"
+	"sync"
 	"syscall"
 	"time"
 
@@ -25,6 +26,7 @@
 	"v.io/v23/verror"
 	"v.io/x/ref/lib/security/audit"
 	"v.io/x/ref/lib/signals"
+	"v.io/x/ref/lib/xrpc"
 	"v.io/x/ref/services/discharger"
 	"v.io/x/ref/services/identity/internal/auditor"
 	"v.io/x/ref/services/identity/internal/blesser"
@@ -103,7 +105,7 @@
 	return 0, nil
 }
 
-func (s *IdentityServer) Serve(ctx *context.T, listenSpec *rpc.ListenSpec, externalHttpAddr, httpAddr, tlsConfig string) {
+func (s *IdentityServer) Serve(ctx *context.T, externalHttpAddr, httpAddr, tlsConfig string) {
 	ctx, err := v23.WithPrincipal(ctx, audit.NewPrincipal(ctx, s.auditor))
 	if err != nil {
 		ctx.Panic(err)
@@ -116,7 +118,7 @@
 		}
 		httpAddr = net.JoinHostPort(httphost, strconv.Itoa(httpportNum))
 	}
-	rpcServer, _, externalAddr := s.Listen(ctx, listenSpec, externalHttpAddr, httpAddr, tlsConfig)
+	rpcServer, _, externalAddr := s.Listen(ctx, externalHttpAddr, httpAddr, tlsConfig)
 	fmt.Printf("HTTP_ADDR=%s\n", externalAddr)
 	if len(s.rootedObjectAddrs) > 0 {
 		fmt.Printf("NAME=%s\n", s.rootedObjectAddrs[0].Name())
@@ -127,9 +129,7 @@
 	}
 }
 
-func (s *IdentityServer) Listen(ctx *context.T, listenSpec *rpc.ListenSpec, externalHttpAddr, httpAddr, tlsConfig string) (rpc.Server, []string, string) {
-	// Setup handlers
-
+func (s *IdentityServer) Listen(ctx *context.T, externalHttpAddr, httpAddr, tlsConfig string) (rpc.XServer, []string, string) {
 	// json-encoded public key and blessing names of this server
 	principal := v23.GetPrincipal(ctx)
 	http.Handle("/auth/blessing-root", handlers.BlessingRoot{principal})
@@ -139,7 +139,7 @@
 		ctx.Fatalf("macaroonKey generation failed: %v", err)
 	}
 
-	rpcServer, published, err := s.setupBlessingServices(ctx, listenSpec, macaroonKey)
+	rpcServer, published, err := s.setupBlessingServices(ctx, macaroonKey)
 	if err != nil {
 		ctx.Fatalf("Failed to setup vanadium services for blessing: %v", err)
 	}
@@ -209,18 +209,15 @@
 
 // Starts the Vanadium and HTTP services for blessing, and the Vanadium service for discharging.
 // All Vanadium services are started on the same port.
-func (s *IdentityServer) setupBlessingServices(ctx *context.T, listenSpec *rpc.ListenSpec, macaroonKey []byte) (rpc.Server, []string, error) {
-	server, err := v23.NewServer(ctx)
-	if err != nil {
-		return nil, nil, fmt.Errorf("failed to create new rpc.Server: %v", err)
-	}
-
+func (s *IdentityServer) setupBlessingServices(ctx *context.T, macaroonKey []byte) (rpc.XServer, []string, error) {
+	disp := newDispatcher(macaroonKey, s.oauthBlesserParams)
 	principal := v23.GetPrincipal(ctx)
 	objectAddr := naming.Join(s.mountNamePrefix, fmt.Sprintf("%v", principal.BlessingStore().Default()))
-	if s.rootedObjectAddrs, err = server.Listen(*listenSpec); err != nil {
-		defer server.Stop()
-		return nil, nil, fmt.Errorf("server.Listen(%v) failed: %v", *listenSpec, err)
+	server, err := xrpc.NewDispatchingServer(ctx, objectAddr, disp)
+	if err != nil {
+		return nil, nil, err
 	}
+	s.rootedObjectAddrs = server.Status().Endpoints
 	var rootedObjectAddr string
 	if naming.Rooted(objectAddr) {
 		rootedObjectAddr = objectAddr
@@ -229,49 +226,53 @@
 	} else {
 		rootedObjectAddr = s.rootedObjectAddrs[0].Name()
 	}
-
-	params := oauthBlesserParams(s.oauthBlesserParams, rootedObjectAddr)
-	dispatcher := newDispatcher(macaroonKey, params)
-	if err := server.ServeDispatcher(objectAddr, dispatcher); err != nil {
-		return nil, nil, fmt.Errorf("failed to start Vanadium services: %v", err)
-	}
+	disp.activate(rootedObjectAddr)
 	ctx.Infof("Vanadium Blessing and discharger services will be published at %v", rootedObjectAddr)
-
 	// Start the HTTP Handler for the OAuth2 access token based blesser.
-	http.Handle("/auth/google/bless", handlers.NewOAuthBlessingHandler(ctx, params))
-
+	s.oauthBlesserParams.DischargerLocation = naming.Join(rootedObjectAddr, dischargerService)
+	http.Handle("/auth/google/bless", handlers.NewOAuthBlessingHandler(ctx, s.oauthBlesserParams))
 	return server, []string{rootedObjectAddr}, nil
 }
 
 // newDispatcher returns a dispatcher for both the blessing and the
 // discharging service.
-func newDispatcher(macaroonKey []byte, blesserParams blesser.OAuthBlesserParams) rpc.Dispatcher {
-	d := dispatcher(map[string]interface{}{
-		macaroonService:     blesser.NewMacaroonBlesserServer(macaroonKey),
-		dischargerService:   discharger.DischargerServer(dischargerlib.NewDischarger()),
-		oauthBlesserService: blesser.NewOAuthBlesserServer(blesserParams),
-	})
-	// Set up the glob invoker.
-	var children []string
-	for k, _ := range d {
-		children = append(children, k)
-	}
-	d[""] = rpc.ChildrenGlobberInvoker(children...)
+func newDispatcher(macaroonKey []byte, blesserParams blesser.OAuthBlesserParams) *dispatcher {
+	d := &dispatcher{}
+	d.macaroonKey = macaroonKey
+	d.blesserParams = blesserParams
+	d.wg.Add(1) // Will be removed at activate.
 	return d
 }
 
-type dispatcher map[string]interface{}
+type dispatcher struct {
+	m             map[string]interface{}
+	wg            sync.WaitGroup
+	macaroonKey   []byte
+	blesserParams blesser.OAuthBlesserParams
+}
 
-func (d dispatcher) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
-	if invoker := d[suffix]; invoker != nil {
+func (d *dispatcher) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
+	d.wg.Wait() // Wait until activate is called.
+	if invoker := d.m[suffix]; invoker != nil {
 		return invoker, security.AllowEveryone(), nil
 	}
 	return nil, nil, verror.New(verror.ErrNoExist, nil, suffix)
 }
 
-func oauthBlesserParams(inputParams blesser.OAuthBlesserParams, servername string) blesser.OAuthBlesserParams {
-	inputParams.DischargerLocation = naming.Join(servername, dischargerService)
-	return inputParams
+func (d *dispatcher) activate(serverName string) {
+	d.blesserParams.DischargerLocation = naming.Join(serverName, dischargerService)
+	d.m = map[string]interface{}{
+		macaroonService:     blesser.NewMacaroonBlesserServer(d.macaroonKey),
+		dischargerService:   discharger.DischargerServer(dischargerlib.NewDischarger()),
+		oauthBlesserService: blesser.NewOAuthBlesserServer(d.blesserParams),
+	}
+	// Set up the glob invoker.
+	var children []string
+	for k, _ := range d.m {
+		children = append(children, k)
+	}
+	d.m[""] = rpc.ChildrenGlobberInvoker(children...)
+	d.wg.Done() // Trigger any pending lookups.
 }
 
 func runHTTPSServer(ctx *context.T, addr, tlsConfig string) {