blob: 3f8c15ce6723e66f5ae4e6553ead56f2dad16a64 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vango
import (
"fmt"
"sort"
"strings"
"time"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/conventions"
"v.io/v23/discovery"
"v.io/v23/flow"
"v.io/v23/naming"
"v.io/v23/options"
"v.io/v23/rpc"
"v.io/v23/security"
)
type echoServer struct{}
func (*echoServer) Echo(ctx *context.T, call rpc.ServerCall, arg string) (string, error) {
ctx.Infof("echoServer got message '%s' from %v", arg, call.RemoteEndpoint())
return arg, nil
}
func runServer(ctx *context.T, name string) error {
_, server, err := v23.WithNewServer(ctx, name, &echoServer{}, security.AllowEveryone())
if err != nil {
return err
}
ctx.Infof("Server listening on %v", server.Status().Endpoints)
ctx.Infof("Server listen errors: %v", server.Status().ListenErrors)
return nil
}
func runClient(ctx *context.T, name string) error {
summary, err := runTimedCall(ctx, name, "new connection")
if err != nil {
return err
}
ctx.Infof("Client success: %v", summary)
summary, err = runTimedCall(ctx, name, "cached connection")
if err != nil {
return err
}
ctx.Infof("Client success: %v", summary)
return nil
}
func runTimedCall(ctx *context.T, name, message string) (string, error) {
summary := fmt.Sprintf("[%s] to %v", message, name)
start := time.Now()
call, err := v23.GetClient(ctx).StartCall(ctx, name, "Echo", []interface{}{message})
if err != nil {
return summary, err
}
var recvd string
if err := call.Finish(&recvd); err != nil {
return summary, err
}
elapsed := time.Now().Sub(start)
if recvd != message {
return summary, fmt.Errorf("got [%s], want [%s]", recvd, message)
}
me := security.LocalBlessingNames(ctx, call.Security())
them, _ := call.RemoteBlessings()
return fmt.Sprintf("%s in %v (THEM:%v EP:%v) (ME:%v)", summary, elapsed, them, call.Security().RemoteEndpoint(), me), nil
}
func username(blessingNames []string) string {
var ret []string
for _, p := range conventions.ParseBlessingNames(blessingNames...) {
ret = append(ret, p.User)
}
return strings.Join(ret, ",")
}
func mountName(ctx *context.T, addendums ...string) string {
var (
p = v23.GetPrincipal(ctx)
b, _ = p.BlessingStore().Default()
names = conventions.ParseBlessingNames(security.BlessingNames(p, b)...)
)
if len(names) == 0 {
return ""
}
return naming.Join(append([]string{names[0].Home()}, addendums...)...)
}
func addRegisteredProto(ls *rpc.ListenSpec, proto, addr string) {
for _, p := range flow.RegisteredProtocols() {
if p == proto {
ls.Addrs = append(ls.Addrs, rpc.ListenAddrs{{Protocol: p, Address: addr}}...)
}
}
}
func serverAddrs(status rpc.ServerStatus) []string {
var addrs []string
for _, ep := range status.Endpoints {
addrs = append(addrs, fmt.Sprintf("(%v, %v)", ep.Addr().Network(), ep.Addr()))
}
sort.Strings(addrs)
return addrs
}
func newPeer(ctx *context.T, u discovery.Update) (*peer, error) {
var (
addrs []string
usernames = make(map[string]bool)
me = naming.MountEntry{IsLeaf: true}
ns = v23.GetNamespace(ctx)
)
for _, vname := range u.Addresses() {
entry, err := ns.Resolve(ctx, vname)
if err != nil {
ctx.Errorf("Failed to resolve advertised address [%v]: %v", vname, err)
continue
}
for _, s := range entry.Servers {
epstr, _ := naming.SplitAddressName(s.Server) // suffix should be empty since the server address is what is advertised.
ep, err := naming.ParseEndpoint(epstr)
if err != nil {
ctx.Errorf("Failed to resolve advertised address [%v] into an endpoint: %v", epstr, err)
continue
}
addrs = append(addrs, fmt.Sprintf("(%v, %v)", ep.Addr().Network(), ep.Addr()))
usernames[username(ep.BlessingNames())] = true
me.Servers = append(me.Servers, s)
}
}
if len(usernames) == 0 {
return nil, fmt.Errorf("could not determine user associated with AdId: %v, addrs: %v", u.Id(), u.Addresses())
}
ulist := make([]string, 0, len(usernames))
for u := range usernames {
ulist = append(ulist, u)
}
return &peer{
username: strings.Join(ulist, ", "),
description: fmt.Sprintf("%v at %v (AdId: %v)", ulist, addrs, u.Id()),
adId: u.Id(),
preresolved: options.Preresolved{&me},
}, nil
}
type peer struct {
username string // Username claimed by the advertisement
description string
preresolved options.Preresolved
adId discovery.AdId
}
func (p *peer) call(ctx *context.T, message string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
start := time.Now()
call, err := v23.GetClient(ctx).StartCall(ctx, "", "Echo", []interface{}{message}, p.preresolved)
if err != nil {
return "", err
}
var recvd string
if err := call.Finish(&recvd); err != nil {
return "", err
}
elapsed := time.Now().Sub(start)
if recvd != message {
return "", fmt.Errorf("got [%s], want [%s]", recvd, message)
}
them, _ := call.RemoteBlessings()
theiraddr := call.Security().RemoteEndpoint().Addr()
return fmt.Sprintf("Called %v at (%v, %v) in %v, and said [%v]", username(them), theiraddr.Network(), theiraddr, elapsed, message), nil
}