Merge "discovery: support Lost"
diff --git a/cmd/vdl/builtin_vdlroot.go b/cmd/vdl/builtin_vdlroot.go
new file mode 100644
index 0000000..584141e
--- /dev/null
+++ b/cmd/vdl/builtin_vdlroot.go
@@ -0,0 +1,78 @@
+// 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.
+
+// This file is automatically generated, your changes will be lost.
+// See make_builtin_vdlroot.go.
+
+package main
+
+//go:generate v23 go run make_builtin_vdlroot.go
+
+const (
+ // builtinVdlrootData contains a base64-encoded gzip'd tar file. This file
+ // contains all of the VDL files required to run the VDL tool.
+ builtinVdlrootData = `H4sIAAAJbogA/+xaa3PcNnd+v0q/AqN+iJ2udyXfWjsfOq7tuM44tidS0pl6PBosid2FRRIMQWq16e
+S/9znnAOBF8iWJk47ziuPLkgQOzuU5N4Derivddo1ZpF/z87z4x+e8DnHdv3uX/8c1/f/24b2j+Fue
+H925f+fuP9RnZeJ9V+db3WD5P0pnKtwXci0W6rGrd41db1p1+/DonjrZGPWTrnRuu1I96tqNa/xcPS
+oKxYO8aow3zbnJ5/uY/KM3yq1Uu7Feedc1mVGZy43C7dqdm6YyuVrulFb/efzklm93haFZhc1MhZnt
+Rrcq05VaGrVyXZUrW+GhUS+eP3768vipWtnCzPdpymudnem1UQmmKjcrWxmv2l1tiKuaGKtaW61BpT
+XNSoMZDZqlgRB5P9PP9+spNV7jeZqWG581dknUN8M1ISq4TeTn+7T4YJ5vmy5r1f/u773UpVG48AQc
+7e+9Plu/1u0m3T9xmRq+f1ouTe6VevOWfykFfl465WuTWV0o1+SGBs73975ncTxGyi8a+Ypei6qDtB
+XWn+//ynIJxQ/LZGhMbvJLwsnk3y2YcBA4/US1BhkCA2HuZQ7UpTX7J8+rR83a05M3b/FLsXXrrlW6
+WXclYOL39151bRiUxuDRZNDz6rhtjC6V+g8a0xPy8viGq1vrKl3cZIJhcBobCF4x+EQLf7S6rnaq11
+KLN0FvROZDSsNttS5MYjiojKZN9DVSVbw5ocE0wy3fGQzGivyIPXpI9df9/+9AdX39KVdrS7Ogfz57
+1u+vD+f/o6PD+/cm+f/o3p071/n/r7i+uPxPWE2pH7arct3kffbXFF89x8ald0XXSgnQmAJvzmW6J8
+6JJok6nRmjLdg2hdsiBtKYnztL6bV1qm7cuYWAWzwgGpkra0xd2sK2O8xpt8ZUKrerFRJy1dL4daPL
+ksoSU53bxlWcWeZKPTOVaXQLuqyylWuIYD91OJyitM10UewSB7prXYmlM0yvoGrP/COJOiR/EpaoTc
+Sb0SpIGmVdmEbZ3AYKnYdu+7KItMRa/2FYVeXg1bM6WYtkY83yw5wsRuvAIwQ7dmXKIdb7zviHROzo
+Jmvc6KbdfAUcYQ6NapwwR/Qq14LldVfohuGFa9O29cPFwlTzrT2ztcmtnrtmvaC7xQuj61NvoID8U4
+Y/dqijbEXMnv5YWVKaLk5PSNpPmM1lXqUlg58+gvZtlibfZuEaw4DpbRgR6lnxjFtSJSxp6Ln/JCkP
+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`
+)
diff --git a/cmd/vdl/builtin_vdlroot_support.go b/cmd/vdl/builtin_vdlroot_support.go
new file mode 100644
index 0000000..57e0cfa
--- /dev/null
+++ b/cmd/vdl/builtin_vdlroot_support.go
@@ -0,0 +1,100 @@
+// 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 main
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "v.io/x/ref/lib/vdl/build"
+ "v.io/x/ref/lib/vdl/vdlutil"
+)
+
+func extractTarFile(basePath string, reader *tar.Reader) error {
+ for {
+ header, err := reader.Next()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ // If it's a directory, ignore it. We use MkdirAll on all files anyway.
+ if header.FileInfo().IsDir() {
+ continue
+ }
+ fullPath := filepath.Join(basePath, header.Name)
+ if err := os.MkdirAll(filepath.Dir(fullPath), os.FileMode(0755)); err != nil {
+ return err
+ }
+ f, err := os.OpenFile(fullPath, os.O_CREATE|os.O_WRONLY, os.FileMode(header.Mode))
+ if err != nil {
+ return err
+ }
+ n, err := io.Copy(f, reader)
+ if err != nil {
+ return err
+ }
+ if n != header.Size {
+ return fmt.Errorf("while reading %s from archive, wrote %d bytes but was expecting to write %d", header.Name, header.Size, n)
+ }
+ }
+}
+
+func extractBuiltinVdlroot(destDir string) error {
+ decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(builtinVdlrootData))
+ gzipReader, err := gzip.NewReader(decoder)
+ if err != nil {
+ return err
+ }
+ tarReader := tar.NewReader(gzipReader)
+ return extractTarFile(destDir, tarReader)
+}
+
+// maybeExtractBuiltinVdlroot checks to see if VDLROOT is set or can be
+// determined from V23_ROOT. If not, the builtin root VDL definitions are
+// extracted to a new temporary directory and the VDLROOT environment variable
+// is set. cleanupFunc should be called unconditionally (even if there is
+// a non-empty set of errors returned).
+func maybeExtractBuiltinVdlroot() (func() error, *vdlutil.Errors) {
+ noopCleanup := func() error { return nil }
+ if !flagBuiltinVdlroot {
+ return noopCleanup, vdlutil.NewErrors(-1)
+ }
+ errs := vdlutil.NewErrors(-1)
+ build.VdlRootDir(errs)
+ if errs.IsEmpty() {
+ // No errors? We have a vdlroot already and we don't need to do
+ // anything.
+ return noopCleanup, errs
+ }
+ errs.Reset()
+ // Otherwise, we don't have a VDL rootdir.
+ dir, err := ioutil.TempDir("", "vdlroot-")
+ if err != nil {
+ errs.Errorf("TempDir failed, couldn't create temporary VDLROOT: %v", err)
+ return noopCleanup, errs
+ }
+ removeAllCleanup := func() error {
+ return os.RemoveAll(dir)
+ }
+ // Extract the files to the new VDLROOT
+ if err := extractBuiltinVdlroot(dir); err != nil {
+ errs.Errorf("Could not extract builtin VDL types: %v", err)
+ return removeAllCleanup, errs
+ }
+ if err := os.Setenv("VDLROOT", dir); err != nil {
+ errs.Errorf("Setenv(VDLROOT, %q) failed: %v", dir, err)
+ return removeAllCleanup, errs
+ }
+ vdlutil.Vlog.Printf("set VDLROOT to newly-extracted root at %s pid = %d", dir, os.Getpid())
+ return removeAllCleanup, errs
+}
diff --git a/cmd/vdl/doc.go b/cmd/vdl/doc.go
index 5cc386a..7daef03 100644
--- a/cmd/vdl/doc.go
+++ b/cmd/vdl/doc.go
@@ -26,6 +26,9 @@
vdl.config Description of vdl.config files
The vdl flags are:
+ -builtin_vdlroot=false
+ If V23_ROOT and VDLROOT are not set, use built-in VDL definitions for core
+ types
-exts=.vdl
Comma-separated list of valid VDL file name extensions.
-ignore_unknown=false
diff --git a/cmd/vdl/main.go b/cmd/vdl/main.go
index 2810b55..0749c07 100644
--- a/cmd/vdl/main.go
+++ b/cmd/vdl/main.go
@@ -16,6 +16,7 @@
"path/filepath"
"strings"
+ "v.io/jiri/collect"
"v.io/v23/vdlroot/vdltool"
"v.io/x/lib/cmdline"
"v.io/x/lib/textutil"
@@ -32,7 +33,26 @@
}
func main() {
- cmdline.Main(cmdVDL)
+ env := cmdline.EnvFromOS()
+ err := runMain(env)
+ os.Exit(cmdline.ExitCode(err, env.Stderr))
+}
+
+func runMain(env *cmdline.Env) (e error) {
+ args := os.Args[1:]
+ runner, args, err := cmdline.Parse(cmdVDL, env, args)
+ if err != nil {
+ return err
+ }
+ cleanup, errs := maybeExtractBuiltinVdlroot()
+ defer collect.Error(cleanup, &err)
+ if err := checkErrors(errs); err != nil {
+ return err
+ }
+ if err := runner.Run(env, args); err != nil {
+ return err
+ }
+ return nil
}
func checkErrors(errs *vdlutil.Errors) error {
@@ -322,11 +342,12 @@
var (
// Common flags for the tool itself, applicable to all commands.
- flagVerbose bool
- flagMaxErrors int
- flagExts string
- flagVDLConfig string
- flagIgnoreUnknown bool
+ flagVerbose bool
+ flagMaxErrors int
+ flagExts string
+ flagVDLConfig string
+ flagIgnoreUnknown bool
+ flagBuiltinVdlroot bool
// Options for each command.
optCompileStatus bool
@@ -375,6 +396,7 @@
cmdVDL.Flags.StringVar(&flagExts, "exts", ".vdl", "Comma-separated list of valid VDL file name extensions.")
cmdVDL.Flags.StringVar(&flagVDLConfig, "vdl.config", "vdl.config", "Basename of the optional per-package config file.")
cmdVDL.Flags.BoolVar(&flagIgnoreUnknown, "ignore_unknown", false, "Ignore unknown packages provided on the command line.")
+ cmdVDL.Flags.BoolVar(&flagBuiltinVdlroot, "builtin_vdlroot", false, "If V23_ROOT and VDLROOT are not set, use built-in VDL definitions for core types")
// Options for compile.
cmdCompile.Flags.BoolVar(&optCompileStatus, "status", true, "Show package names while we compile")
diff --git a/cmd/vdl/make_builtin_vdlroot.go b/cmd/vdl/make_builtin_vdlroot.go
new file mode 100644
index 0000000..1377fd2
--- /dev/null
+++ b/cmd/vdl/make_builtin_vdlroot.go
@@ -0,0 +1,171 @@
+// 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.
+
+// Command make_builtin_vdlroot runs at v23 go generate time. It emits a Go
+// source file called builtin_vdlroot.go containing a gzip'd version of all
+// the core VDL types required by the VDL tool. This allows the VDL tool to
+// run 'standalone' (i.e. without access to the Vanadium source code).
+//
+// +build ignored
+
+package main
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const (
+ outputPreamble = `// 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.
+
+// This file is automatically generated, your changes will be lost.
+// See make_builtin_vdlroot.go.
+
+package main
+
+//go:generate v23 go run make_builtin_vdlroot.go
+
+const (
+ // builtinVdlrootData contains a base64-encoded gzip'd tar file. This file
+ // contains all of the VDL files required to run the VDL tool.
+ builtinVdlrootData = ` + "`"
+ outputFooter = "`" + `
+)
+`
+)
+
+// writeBytes writes the given bytes to the given writer, returning an error if
+// the underlying Write fails or if the number of bytes written is not equal to
+// len(content).
+func writeBytes(out io.Writer, content []byte) error {
+ n, err := out.Write(content)
+ if err == nil && n != len(content) {
+ err = fmt.Errorf("wrote an unexpected number of bytes, wanted %d, wrote %d", len(content), n)
+ }
+ return err
+}
+
+// writeString writes the given string to the given writer, returning an error
+// if the underlying Write fails or if the number of bytes written is not equal
+// to len(content).
+func writeString(out io.Writer, content string) error {
+ return writeBytes(out, []byte(content))
+}
+
+type wrapWriter struct {
+ writer io.Writer
+ totalWritten int
+}
+
+// Writes b to the underlying writer but inserts a \n every 78 characters. The
+// returned bytes-written count includes the \n characters.
+func (w *wrapWriter) Write(b []byte) (int, error) {
+ const max = 78
+ n := 0
+ for len(b) > 0 {
+ newline := true
+ chunk := max - w.totalWritten%max
+ if len(b) < chunk {
+ chunk = len(b)
+ newline = false
+ }
+ if err := writeBytes(w.writer, b[:chunk]); err != nil {
+ return n, err
+ }
+ n += chunk
+ w.totalWritten += chunk
+ b = b[chunk:]
+ if newline {
+ if err := writeString(w.writer, "\n"); err != nil {
+ return n, err
+ }
+ n++
+ }
+ }
+ return n, nil
+}
+
+// writeVdlrootData creates a gzip'd tar file containing all of the VDL files
+// in vdlroot. The data is encoded as base64. Does not close out.
+func writeVdlrootData(out io.Writer) error {
+ v23root := os.Getenv("V23_ROOT")
+ if v23root == "" {
+ return fmt.Errorf("V23_ROOT is not set")
+ }
+ vdlroot := filepath.Join(v23root, "release", "go", "src", "v.io", "v23", "vdlroot")
+ wrapWriter := &wrapWriter{
+ writer: out,
+ totalWritten: 0,
+ }
+ base64writer := base64.NewEncoder(base64.StdEncoding, wrapWriter)
+ gzipWriter := gzip.NewWriter(base64writer)
+ tarWriter := tar.NewWriter(gzipWriter)
+ walkFn := func(path string, info os.FileInfo, err error) error {
+ if strings.HasSuffix(path, ".vdl") {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ relPath, err := filepath.Rel(vdlroot, path)
+ if err != nil {
+ return err
+ }
+ header := tar.Header{
+ Mode: int64(0644),
+ Name: relPath,
+ Size: int64(len(content)),
+ }
+ if err := tarWriter.WriteHeader(&header); err != nil {
+ return err
+ }
+ return writeBytes(tarWriter, content)
+ }
+ return nil
+ }
+ if err := filepath.Walk(vdlroot, walkFn); err != nil {
+ log.Printf("Walk() failed: %v", err)
+ }
+ if err := tarWriter.Close(); err != nil {
+ log.Printf("Close() of tar file failed: %v", err)
+ return err
+ }
+ if err := gzipWriter.Close(); err != nil {
+ log.Printf("Close() of gzip file failed: %v", err)
+ return err
+ }
+ if err := base64writer.Close(); err != nil {
+ log.Printf("Close() of base64 file failed: %v", err)
+ return err
+ }
+ return nil
+}
+
+func main() {
+ filename := "builtin_vdlroot.go"
+ f, err := os.Create(filename)
+ if err != nil {
+ log.Printf("Create(%q) failed: %v", filename, err)
+ os.Exit(1)
+ }
+ defer f.Close()
+ if err := writeString(f, outputPreamble); err != nil {
+ os.Exit(1)
+ }
+ if err := writeVdlrootData(f); err != nil {
+ os.Exit(1)
+ }
+ if err := writeString(f, outputFooter); err != nil {
+ os.Exit(1)
+ }
+}
diff --git a/cmd/vdl/vdl_test.go b/cmd/vdl/vdl_test.go
index 7a127cd..99f5c5a 100644
--- a/cmd/vdl/vdl_test.go
+++ b/cmd/vdl/vdl_test.go
@@ -8,10 +8,12 @@
"bytes"
"fmt"
"io/ioutil"
+ "os"
"path/filepath"
"strings"
"testing"
+ "v.io/x/lib/envvar"
"v.io/x/ref/test/v23tests"
)
@@ -22,18 +24,7 @@
//go:generate v23 test generate
-// Compares generated VDL files against the copy in the repo.
-func TestVDLGenerator(t *testing.T) {
- testEnv := v23tests.New(t)
- defer testEnv.Cleanup()
- vdlBin := testEnv.BuildGoPkg("v.io/x/ref/cmd/vdl")
-
- // Use vdl to generate Go code from input, into a temporary directory.
- outDir := testEnv.NewTempDir("")
- // TODO(toddw): test the generated java and javascript files too.
- outOpt := fmt.Sprintf("--go-out-dir=%s", outDir)
- vdlBin.Run("generate", "--lang=go", outOpt, testDir)
- // Check that each *.vdl.go file in the testDir matches the generated output.
+func verifyOutput(t *testing.T, outDir string) {
entries, err := ioutil.ReadDir(testDir)
if err != nil {
t.Fatalf("ReadDir(%v) failed: %v", testDir, err)
@@ -62,3 +53,34 @@
t.Fatalf("testDir %s has no golden files *.vdl.go", testDir)
}
}
+
+// Compares generated VDL files against the copy in the repo.
+func TestVDLGenerator(t *testing.T) {
+ testEnv := v23tests.New(t)
+ defer testEnv.Cleanup()
+ vdlBin := testEnv.BuildGoPkg("v.io/x/ref/cmd/vdl")
+
+ // Use vdl to generate Go code from input, into a temporary directory.
+ outDir := testEnv.NewTempDir("")
+ // TODO(toddw): test the generated java and javascript files too.
+ outOpt := fmt.Sprintf("--go-out-dir=%s", outDir)
+ vdlBin.Run("generate", "--lang=go", outOpt, testDir)
+ // Check that each *.vdl.go file in the testDir matches the generated output.
+ verifyOutput(t, outDir)
+}
+
+// Asserts that the VDL command can run to completion without VDLROOT or
+// V23_ROOT being set.
+func TestVDLGeneratorWithNoVDLRoot(t *testing.T) {
+ testEnv := v23tests.New(t)
+ defer testEnv.Cleanup()
+ vdlBin := testEnv.BuildGoPkg("v.io/x/ref/cmd/vdl")
+
+ outDir := testEnv.NewTempDir("")
+ outOpt := fmt.Sprintf("--go-out-dir=%s", outDir)
+ env := envvar.SliceToMap(os.Environ())
+ env["V23_ROOT"] = ""
+ env["VDLROOT"] = ""
+ vdlBin.WithEnv(envvar.MapToSlice(env)...).Run("-v", "--builtin_vdlroot", "generate", "--lang=go", outOpt, testDir)
+ verifyOutput(t, outDir)
+}
diff --git a/lib/vdl/build/build.go b/lib/vdl/build/build.go
index 8ce8ee7..0d6bea5 100644
--- a/lib/vdl/build/build.go
+++ b/lib/vdl/build/build.go
@@ -270,13 +270,20 @@
// neither VDLROOT nor V23_ROOT is specified.
func SrcDirs(errs *vdlutil.Errors) []string {
var srcDirs []string
- if root := vdlRootDir(errs); root != "" {
+ if root := VdlRootDir(errs); root != "" {
srcDirs = append(srcDirs, root)
}
return append(srcDirs, vdlPathSrcDirs(errs)...)
}
-func vdlRootDir(errs *vdlutil.Errors) string {
+// VdlRootDir returns the VDL root directory, based on the VDLPATH, VDLROOT and
+// V23_ROOT environment variables.
+//
+// VDLROOT is a single directory specifying the location of the standard vdl
+// packages. It has the same requirements as VDLPATH components. If VDLROOT is
+// empty, we use V23_ROOT to construct the VDLROOT. An error is reported if
+// neither VDLROOT nor V23_ROOT is specified.
+func VdlRootDir(errs *vdlutil.Errors) string {
vdlroot := os.Getenv("VDLROOT")
if vdlroot == "" {
// Try to construct VDLROOT out of V23_ROOT.
diff --git a/runtime/internal/flow/conn/conn.go b/runtime/internal/flow/conn/conn.go
index a7991c7..ecbd8a9 100644
--- a/runtime/internal/flow/conn/conn.go
+++ b/runtime/internal/flow/conn/conn.go
@@ -346,3 +346,8 @@
c.lastUsedTime = time.Now()
c.mu.Unlock()
}
+
+func (c *Conn) IsEncapsulated() bool {
+ _, ok := c.mp.rw.(*flw)
+ return ok
+}
diff --git a/runtime/internal/flow/errors.vdl b/runtime/internal/flow/errors.vdl
new file mode 100644
index 0000000..8019811
--- /dev/null
+++ b/runtime/internal/flow/errors.vdl
@@ -0,0 +1,15 @@
+// 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 flow
+
+// These messages are constructed so as to avoid embedding a component/method name
+// and are thus more suitable for inclusion in other verrors.
+// This practice of omitting {1}{2} should be used throughout the flow implementations
+// since all of their errors are intended to be used as arguments to higher level errors.
+// TODO(suharshs,toddw): Allow skipping of {1}{2} in vdl generated errors.
+error (
+ WrongObjectInContext(typ string) {"en":
+ "context passed to method of {typ} object, but that object is not attached to the context."}
+)
diff --git a/runtime/internal/flow/errors.vdl.go b/runtime/internal/flow/errors.vdl.go
new file mode 100644
index 0000000..3f4d3b2
--- /dev/null
+++ b/runtime/internal/flow/errors.vdl.go
@@ -0,0 +1,28 @@
+// 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.
+
+// This file was auto-generated by the vanadium vdl tool.
+// Source: errors.vdl
+
+package flow
+
+import (
+ // VDL system imports
+ "v.io/v23/context"
+ "v.io/v23/i18n"
+ "v.io/v23/verror"
+)
+
+var (
+ ErrWrongObjectInContext = verror.Register("v.io/x/ref/runtime/internal/flow.WrongObjectInContext", verror.NoRetry, "{1:}{2:} context passed to method of {3} object, but that object is not attached to the context.")
+)
+
+func init() {
+ i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrWrongObjectInContext.ID), "{1:}{2:} context passed to method of {3} object, but that object is not attached to the context.")
+}
+
+// NewErrWrongObjectInContext returns an error with the ErrWrongObjectInContext ID.
+func NewErrWrongObjectInContext(ctx *context.T, typ string) error {
+ return verror.New(ErrWrongObjectInContext, ctx, typ)
+}
diff --git a/runtime/internal/flow/manager/conncache.go b/runtime/internal/flow/manager/conncache.go
index 92f8348..b3975e2 100644
--- a/runtime/internal/flow/manager/conncache.go
+++ b/runtime/internal/flow/manager/conncache.go
@@ -151,6 +151,10 @@
delete(c.ridCache, e.rid)
continue
}
+ if e.conn.IsEncapsulated() {
+ // Killing a proxied connection doesn't save us any FD resources, just memory.
+ continue
+ }
pq = append(pq, e)
}
sort.Sort(pq)
diff --git a/runtime/internal/flow/manager/manager.go b/runtime/internal/flow/manager/manager.go
index 2490352..60fa43e 100644
--- a/runtime/internal/flow/manager/manager.go
+++ b/runtime/internal/flow/manager/manager.go
@@ -20,13 +20,17 @@
"v.io/v23/security"
"v.io/v23/verror"
+ iflow "v.io/x/ref/runtime/internal/flow"
"v.io/x/ref/runtime/internal/flow/conn"
"v.io/x/ref/runtime/internal/lib/upcqueue"
inaming "v.io/x/ref/runtime/internal/naming"
"v.io/x/ref/runtime/internal/rpc/version"
)
-const reconnectDelay = 50 * time.Millisecond
+const (
+ reconnectDelay = 50 * time.Millisecond
+ reapCacheInterval = 5 * time.Minute
+)
type manager struct {
rid naming.RoutingID
@@ -52,19 +56,27 @@
listeners: []flow.Listener{},
}
go func() {
- select {
- case <-ctx.Done():
- m.mu.Lock()
- listeners := m.listeners
- m.listeners = nil
- m.mu.Unlock()
- for _, ln := range listeners {
- ln.Close()
+ ticker := time.NewTicker(reapCacheInterval)
+ for {
+ select {
+ case <-ctx.Done():
+ m.mu.Lock()
+ listeners := m.listeners
+ m.listeners = nil
+ m.mu.Unlock()
+ for _, ln := range listeners {
+ ln.Close()
+ }
+ m.cache.Close(ctx)
+ m.q.Close()
+ m.wg.Wait()
+ ticker.Stop()
+ close(m.closed)
+ return
+ case <-ticker.C:
+ // Periodically kill closed connections.
+ m.cache.KillConnections(ctx, 0)
}
- m.cache.Close(ctx)
- m.q.Close()
- m.wg.Wait()
- close(m.closed)
}
}()
return m
@@ -76,6 +88,9 @@
// The flow.Manager associated with ctx must be the receiver of the method,
// otherwise an error is returned.
func (m *manager) Listen(ctx *context.T, protocol, address string) error {
+ if err := m.validateContext(ctx); err != nil {
+ return err
+ }
if protocol == inaming.Network {
return m.proxyListen(ctx, address)
}
@@ -298,7 +313,9 @@
// The flow.Manager associated with ctx must be the receiver of the method,
// otherwise an error is returned.
func (m *manager) Accept(ctx *context.T) (flow.Flow, error) {
- // TODO(suharshs): Ensure that m is attached to ctx.
+ if err := m.validateContext(ctx); err != nil {
+ return nil, err
+ }
item, err := m.q.Get(ctx.Done())
switch {
case err == upcqueue.ErrQueueIsClosed:
@@ -319,6 +336,9 @@
// The flow.Manager associated with ctx must be the receiver of the method,
// otherwise an error is returned.
func (m *manager) Dial(ctx *context.T, remote naming.Endpoint, fn flow.BlessingsForPeer) (flow.Flow, error) {
+ if err := m.validateContext(ctx); err != nil {
+ return nil, err
+ }
var fh conn.FlowHandler
if m.rid != naming.NullRoutingID {
fh = &flowHandler{q: m.q}
@@ -436,6 +456,13 @@
return m.closed
}
+func (m *manager) validateContext(ctx *context.T) error {
+ if v23.ExperimentalGetFlowManager(ctx) != m {
+ return flow.NewErrBadArg(ctx, iflow.NewErrWrongObjectInContext(ctx, "manager"))
+ }
+ return nil
+}
+
func dial(ctx *context.T, p flow.Protocol, protocol, address string) (flow.Conn, error) {
if p != nil {
var timeout time.Duration
diff --git a/runtime/internal/flow/manager/manager_test.go b/runtime/internal/flow/manager/manager_test.go
index cce80f9..02a96d3 100644
--- a/runtime/internal/flow/manager/manager_test.go
+++ b/runtime/internal/flow/manager/manager_test.go
@@ -15,7 +15,7 @@
"v.io/v23/flow"
"v.io/v23/naming"
- _ "v.io/x/ref/runtime/factories/fake"
+ "v.io/x/ref/runtime/factories/fake"
"v.io/x/ref/runtime/internal/flow/conn"
"v.io/x/ref/runtime/internal/flow/flowtest"
"v.io/x/ref/test"
@@ -33,12 +33,14 @@
ctx, shutdown := v23.Init()
am := New(ctx, naming.FixedRoutingID(0x5555))
- if err := am.Listen(ctx, "tcp", "127.0.0.1:0"); err != nil {
+ actx := fake.SetFlowManager(ctx, am)
+ if err := am.Listen(actx, "tcp", "127.0.0.1:0"); err != nil {
t.Fatal(err)
}
dm := New(ctx, naming.FixedRoutingID(0x1111))
+ dctx := fake.SetFlowManager(ctx, dm)
- testFlows(t, ctx, dm, am, flowtest.BlessingsForPeer)
+ testFlows(t, dctx, actx, flowtest.BlessingsForPeer)
shutdown()
<-am.Closed()
@@ -50,24 +52,26 @@
ctx, shutdown := v23.Init()
am := New(ctx, naming.FixedRoutingID(0x5555))
- if err := am.Listen(ctx, "tcp", "127.0.0.1:0"); err != nil {
+ actx := fake.SetFlowManager(ctx, am)
+ if err := am.Listen(actx, "tcp", "127.0.0.1:0"); err != nil {
t.Fatal(err)
}
dm := New(ctx, naming.FixedRoutingID(0x1111))
+ dctx := fake.SetFlowManager(ctx, dm)
// At first the cache should be empty.
if got, want := len(dm.(*manager).cache.addrCache), 0; got != want {
t.Fatalf("got cache size %v, want %v", got, want)
}
// After dialing a connection the cache should hold one connection.
- testFlows(t, ctx, dm, am, flowtest.BlessingsForPeer)
+ testFlows(t, dctx, actx, flowtest.BlessingsForPeer)
if got, want := len(dm.(*manager).cache.addrCache), 1; got != want {
t.Fatalf("got cache size %v, want %v", got, want)
}
old := dm.(*manager).cache.ridCache[am.RoutingID()]
// After dialing another connection the cache should still hold one connection
// because the connections should be reused.
- testFlows(t, ctx, dm, am, flowtest.BlessingsForPeer)
+ testFlows(t, dctx, actx, flowtest.BlessingsForPeer)
if got, want := len(dm.(*manager).cache.addrCache), 1; got != want {
t.Errorf("got cache size %v, want %v", got, want)
}
@@ -85,14 +89,16 @@
ctx, shutdown := v23.Init()
am := New(ctx, naming.FixedRoutingID(0x5555))
- if err := am.Listen(ctx, "tcp", "127.0.0.1:0"); err != nil {
+ actx := fake.SetFlowManager(ctx, am)
+ if err := am.Listen(actx, "tcp", "127.0.0.1:0"); err != nil {
t.Fatal(err)
}
dm := New(ctx, naming.FixedRoutingID(0x1111))
- testFlows(t, ctx, dm, am, flowtest.BlessingsForPeer)
+ dctx := fake.SetFlowManager(ctx, dm)
+ testFlows(t, dctx, actx, flowtest.BlessingsForPeer)
// Now am should be able to make a flow to dm even though dm is not listening.
- testFlows(t, ctx, am, dm, flowtest.BlessingsForPeer)
+ testFlows(t, actx, dctx, flowtest.BlessingsForPeer)
shutdown()
<-am.Closed()
@@ -104,17 +110,20 @@
ctx, shutdown := v23.Init()
am := New(ctx, naming.FixedRoutingID(0x5555))
- if err := am.Listen(ctx, "tcp", "127.0.0.1:0"); err != nil {
+ actx := fake.SetFlowManager(ctx, am)
+ if err := am.Listen(actx, "tcp", "127.0.0.1:0"); err != nil {
t.Fatal(err)
}
nulldm := New(ctx, naming.NullRoutingID)
- _, af := testFlows(t, ctx, nulldm, am, flowtest.BlessingsForPeer)
+ nctx := fake.SetFlowManager(ctx, nulldm)
+ _, af := testFlows(t, nctx, actx, flowtest.BlessingsForPeer)
// Ensure that the remote blessings of the underlying conn of the accepted flow are zero.
if rBlessings := af.Conn().(*conn.Conn).RemoteBlessings(); !rBlessings.IsZero() {
t.Errorf("got %v, want zero-value blessings", rBlessings)
}
dm := New(ctx, naming.FixedRoutingID(0x1111))
- _, af = testFlows(t, ctx, dm, am, flowtest.BlessingsForPeer)
+ dctx := fake.SetFlowManager(ctx, dm)
+ _, af = testFlows(t, dctx, actx, flowtest.BlessingsForPeer)
// Ensure that the remote blessings of the underlying conn of the accepted flow are
// non-zero if we did specify a RoutingID.
if rBlessings := af.Conn().(*conn.Conn).RemoteBlessings(); rBlessings.IsZero() {
@@ -127,20 +136,17 @@
<-nulldm.Closed()
}
-func testFlows(t *testing.T, ctx *context.T, dm, am flow.Manager, bFn flow.BlessingsForPeer) (df, af flow.Flow) {
- eps := am.ListeningEndpoints()
- if len(eps) == 0 {
- t.Fatalf("no endpoints listened on")
- }
- ep := eps[0]
+func testFlows(t *testing.T, dctx, actx *context.T, bFn flow.BlessingsForPeer) (df, af flow.Flow) {
+ am := v23.ExperimentalGetFlowManager(actx)
+ ep := am.ListeningEndpoints()[0]
var err error
- df, err = dm.Dial(ctx, ep, bFn)
+ df, err = v23.ExperimentalGetFlowManager(dctx).Dial(dctx, ep, bFn)
if err != nil {
t.Fatal(err)
}
want := "do you read me?"
writeLine(df, want)
- af, err = am.Accept(ctx)
+ af, err = am.Accept(actx)
if err != nil {
t.Fatal(err)
}
diff --git a/services/agent/vbecome/vbecome.go b/services/agent/vbecome/vbecome.go
index 15abcc0..1b91eb2 100644
--- a/services/agent/vbecome/vbecome.go
+++ b/services/agent/vbecome/vbecome.go
@@ -109,6 +109,11 @@
}
}
+ // Clear out the environment variable before starting the child.
+ if err = ref.EnvClearCredentials(); err != nil {
+ return err
+ }
+
// Start an agent server.
i := ipc.NewIPC()
if err := server.ServeAgent(i, principal); err != nil {