veyron/lib/modules: add wspr module and a tool to start all services

Change-Id: I2684c5b270417f61bb298d2e4d2b61b242fec930
diff --git a/lib/flags/doc.go b/lib/flags/doc.go
index 49a7360..b752f0a 100644
--- a/lib/flags/doc.go
+++ b/lib/flags/doc.go
@@ -1,17 +1,18 @@
-// Package flags provides definitions for commonly used flags and where
-// appropriate, implementations of the flag.Value interface for those flags
-// to ensure that only valid values of those flags are supplied. Some of these
-// flags may also be specified using environment variables directly for
-// are documented accordingly; in these cases the command line value takes
+// Package flags provides definitions for commonly used flags and, where
+// appropriate, implementations of the flag.Value interface for those flags to
+// ensure that only valid values of those flags are supplied. Some of these
+// flags may also be specified using environment variables directly and are
+// documented accordingly; in these cases the command line value takes
 // precedence over the environment variable.
-// Flags are defined as 'groups' of related flags so that caller may choose
-// which ones to use without having to be burdened with the full set. The
-// groups may be used directly or via the Flags type that aggregates multiple
-// groups. In all cases, the flags are registered with a supplied
-// flag.FlagSet and hence are not forced onto the command line
-// unless the caller passes in flag.CommandLine as the flag.FlagSet to use.
 //
-// In general, this package will be used by veyron profiles and the
-// runtime implementations, but can also be used by any application
-// that wants access to the flags and environment variables it supports.
+// Flags are defined as 'groups' of related flags so that the caller may choose
+// which ones to use without having to be burdened with the full set. The groups
+// may be used directly or via the Flags type that aggregates multiple
+// groups. In all cases, the flags are registered with a supplied flag.FlagSet
+// and hence are not forced onto the command line unless the caller passes in
+// flag.CommandLine as the flag.FlagSet to use.
+//
+// In general, this package will be used by veyron profiles and the runtime
+// implementations, but can also be used by any application that wants access to
+// the flags and environment variables it supports.
 package flags
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index bf4e6d4..add670f 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -67,6 +67,7 @@
 	MTCommand          = "mt"
 	LSExternalCommand  = "lse"
 	ProxyServerCommand = "proxyd"
+	WSPRCommand        = "wsprd"
 	ShellCommand       = "sh"
 )
 
@@ -93,7 +94,11 @@
 		run a glob command as an external subprocess`)
 	shell.AddSubprocess(ProxyServerCommand, `<name>...
 		run a proxy server mounted at the specified names`)
-	//	shell.AddSubprocess(ShellCommand, subshell, "")
+	// TODO(sadovsky): It's unfortunate that we must duplicate help strings
+	// between RegisterChild and AddSubprocess. Will be fixed by my proposed
+	// refactoring.
+	shell.AddSubprocess(WSPRCommand, usageWSPR())
+	//shell.AddSubprocess(ShellCommand, subshell, "")
 
 	shell.AddFunction(LSCommand, ls, `<glob>...
 	issues glob requests using the current processes namespace library`)
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index 3f6ff42..f3adb9f 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -40,7 +40,7 @@
 func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	fl, args, err := parseListenFlags(args)
 	if err != nil {
-		return fmt.Errorf("failed parsing args: %s", err)
+		return fmt.Errorf("failed to parse args: %s", err)
 	}
 	if err := checkArgs(args, 2, "<message> <name>"); err != nil {
 		return err
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 9c4fec0..9326030 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -36,9 +36,8 @@
 	r := rt.R()
 	fl, args, err := parseListenFlags(args)
 	if err != nil {
-		return fmt.Errorf("failed parsing args: %s", err)
+		return fmt.Errorf("failed to parse args: %s", err)
 	}
-	//	args = fl.Args()
 	lspec := initListenSpec(fl)
 	server, err := r.NewServer(options.ServesMountTable(true))
 	if err != nil {
@@ -72,7 +71,7 @@
 
 func ls(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	details := false
-	args = args[1:] // skip over comamnd name
+	args = args[1:] // skip over command name
 	if len(args) > 0 && args[0] == "-l" {
 		details = true
 		args = args[1:]
diff --git a/lib/modules/core/proxy.go b/lib/modules/core/proxy.go
index 7290543..3cc63ea 100644
--- a/lib/modules/core/proxy.go
+++ b/lib/modules/core/proxy.go
@@ -20,8 +20,10 @@
 func proxyServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	fl, args, err := parseListenFlags(args)
 	if err != nil {
-		return fmt.Errorf("failed parsing args: %s", err)
-	} //	args = fl.Args()
+		return fmt.Errorf("failed to parse args: %s", err)
+	}
+	// TODO(sadovsky): Why does this require >=1 arg? Seems 0 should be fine.
+	// Also note, we have no way to specify ">=0".
 	if err := checkArgs(args, -1, ""); err != nil {
 		return err
 	}
@@ -63,7 +65,6 @@
 	for _, p := range pub.Published() {
 		fmt.Fprintf(stdout, "PUBLISHED_PROXY_NAME=%s\n", p)
 	}
-	fmt.Fprintf(stdout, "READY")
 	modules.WaitForEOF(stdin)
 	return nil
 }
diff --git a/lib/modules/core/util.go b/lib/modules/core/util.go
index 81b6101..a429651 100644
--- a/lib/modules/core/util.go
+++ b/lib/modules/core/util.go
@@ -9,13 +9,19 @@
 	"veyron.io/veyron/veyron/lib/flags"
 )
 
+func parseFlags(fl *flags.Flags, args []string) error {
+	if len(args) == 0 {
+		return nil
+	}
+	return fl.Parse(args[1:])
+}
+
+// parseListenFlags parses the given args using just the flags and env vars
+// defined in the veyron/lib/flags package.
 func parseListenFlags(args []string) (*flags.Flags, []string, error) {
 	fs := flag.NewFlagSet("modules/core", flag.ContinueOnError)
 	fl := flags.CreateAndRegister(fs, flags.Listen)
-	if len(args) == 0 {
-		return fl, []string{}, nil
-	}
-	err := fl.Parse(args[1:])
+	err := parseFlags(fl, args)
 	return fl, fl.Args(), err
 }
 
@@ -28,7 +34,7 @@
 	}
 }
 
-// checkArgs checks for the expected number of args in args. A -ve
+// checkArgs checks for the expected number of args in args. A negative
 // value means at least that number of args are expected.
 func checkArgs(args []string, expected int, usage string) error {
 	got := len(args)
diff --git a/lib/modules/core/wspr.go b/lib/modules/core/wspr.go
new file mode 100644
index 0000000..2c242e8
--- /dev/null
+++ b/lib/modules/core/wspr.go
@@ -0,0 +1,72 @@
+package core
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"strings"
+
+	"veyron.io/veyron/veyron2"
+	"veyron.io/veyron/veyron2/options"
+
+	"veyron.io/veyron/veyron/lib/flags"
+	"veyron.io/veyron/veyron/lib/modules"
+	"veyron.io/wspr/veyron/services/wsprd/wspr"
+)
+
+var (
+	// TODO(sadovsky): We should restructure things so that we can avoid
+	// duplicating code between subprocess command impls and actual main()'s.
+	fs *flag.FlagSet = flag.NewFlagSet("wspr", flag.ContinueOnError)
+
+	port   *int    = fs.Int("port", 0, "Port to listen on.")
+	identd *string = fs.String("identd", "", "identd server name. Must be set.")
+	// TODO(ataly, ashankar, bjornick): Remove this flag once the old security
+	// model is killed.
+	newSecurityModel *bool = fs.Bool("new_security_model", false, "Use the new security model.")
+
+	fl *flags.Flags = flags.CreateAndRegister(fs, flags.Listen)
+)
+
+func usageWSPR() string {
+	res := []string{}
+	fs.VisitAll(func(f *flag.Flag) {
+		format := "  -%s=%s: %s"
+		if getter, ok := f.Value.(flag.Getter); ok {
+			if _, ok := getter.Get().(string); ok {
+				// put quotes on the value
+				format = "  -%s=%q: %s"
+			}
+		}
+		res = append(res, fmt.Sprintf(format, f.Name, f.DefValue, f.Usage))
+	})
+	return strings.Join(res, "\n") + "\n"
+}
+
+func init() {
+	modules.RegisterChild(WSPRCommand, usageWSPR(), startWSPR)
+}
+
+func startWSPR(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if err := parseFlags(fl, args); err != nil {
+		return fmt.Errorf("failed to parse args: %s", err)
+	}
+	args = fl.Args()
+
+	var opts []veyron2.ROpt
+	if *newSecurityModel {
+		opts = append(opts, options.ForceNewSecurityModel{})
+	}
+
+	proxy := wspr.NewWSPR(*port, initListenSpec(fl), *identd)
+	defer proxy.Shutdown()
+
+	addr := proxy.Listen()
+	go func() {
+		proxy.Serve()
+	}()
+
+	fmt.Fprintf(stdout, "WSPR_ADDR=%s\n", addr.String())
+	modules.WaitForEOF(stdin)
+	return nil
+}