wspr/nacl: Changes to run WSPR in nacl

Change-Id: Ica3a46b28ef1cf0574b5ae6cf5948467374665f7
diff --git a/lib/netconfig/ipaux_linux.go b/lib/netconfig/ipaux_linux.go
index 49945d1..4003001 100644
--- a/lib/netconfig/ipaux_linux.go
+++ b/lib/netconfig/ipaux_linux.go
@@ -1,3 +1,5 @@
+// +build linux
+
 package netconfig
 
 // We connect to the Netlink Route socket and parse messages to
diff --git a/lib/netconfig/ipaux.go b/lib/netconfig/ipaux_other.go
similarity index 82%
rename from lib/netconfig/ipaux.go
rename to lib/netconfig/ipaux_other.go
index ffade53..5345a8f 100644
--- a/lib/netconfig/ipaux.go
+++ b/lib/netconfig/ipaux_other.go
@@ -1,4 +1,5 @@
-// +build plan9 windows
+// +build plan9 windows nacl
+// TODO(bprosnitz) Should change for nacl?
 
 package netconfig
 
@@ -40,8 +41,13 @@
 }
 
 func NewNetConfigWatcher() (NetConfigWatcher, error) {
+	w := &timerNetConfigWatcher{}
 	w.c = make(chan struct{})
 	w.stop = make(chan struct{}, 1)
 	go w.watcher()
 	return w, nil
 }
+
+func GetIPRoutes(defaultOnly bool) []*IPRoute {
+	panic("Not yet implemented")
+}
diff --git a/profiles/platform_darwin.go b/profiles/platform_darwin.go
index e6b2af3..c4a36fa 100644
--- a/profiles/platform_darwin.go
+++ b/profiles/platform_darwin.go
@@ -1,5 +1,3 @@
-// +build darwin
-
 package profiles
 
 // #include <sys/utsname.h>
diff --git a/profiles/platform_linux.go b/profiles/platform_linux.go
index 8cd0ca2..f0d969f 100644
--- a/profiles/platform_linux.go
+++ b/profiles/platform_linux.go
@@ -1,5 +1,3 @@
-// +build linux
-
 package profiles
 
 import (
diff --git a/profiles/platform_nacl.go b/profiles/platform_nacl.go
new file mode 100644
index 0000000..da9ed65
--- /dev/null
+++ b/profiles/platform_nacl.go
@@ -0,0 +1,21 @@
+package profiles
+
+import (
+	"veyron.io/veyron/veyron2"
+)
+
+// Platform returns the description of the Platform this process is running on.
+// A default value for veyron2.Platform is provided even if an error is
+// returned; nil is never returned for the first return result.
+func Platform() (*veyron2.Platform, error) {
+	d := &veyron2.Platform{
+		Vendor:  "google",
+		Model:   "generic",
+		System:  "nacl",
+		Version: "0",
+		Release: "0",
+		Machine: "0",
+		Node:    "0",
+	}
+	return d, nil
+}
diff --git a/services/wsprd/wspr.go b/services/wsprd/wspr.go
index c169046..e45234c 100644
--- a/services/wsprd/wspr.go
+++ b/services/wsprd/wspr.go
@@ -11,12 +11,13 @@
 )
 
 func main() {
+	port := flag.Int("port", 8124, "Port to listen on.")
 	identd := flag.String("identd", "", "The endpoint for the identd server.  This must be set.")
 	flag.Parse()
 
 	rt.Init()
 
-	proxy := wspr.NewWSPR(*roaming.ListenSpec, *identd)
+	proxy := wspr.NewWSPR(*port, *roaming.ListenSpec, *identd)
 	defer proxy.Shutdown()
 	go func() {
 		proxy.Run()
diff --git a/services/wsprd/wspr/pipe.go b/services/wsprd/wspr/pipe.go
index 85f993d..a04c2af 100644
--- a/services/wsprd/wspr/pipe.go
+++ b/services/wsprd/wspr/pipe.go
@@ -193,10 +193,14 @@
 
 // Upon first connect, we send a message with the wsprConfig.
 func (p *pipe) sendInitialMessage() {
+	// TODO(bprosnitz) Use the same root lookup as the rest of veyron so that this is consistent.
 	mounttableRoots := strings.Split(os.Getenv("NAMESPACE_ROOT"), ",")
 	if len(mounttableRoots) == 1 && mounttableRoots[0] == "" {
 		mounttableRoots = []string{}
 	}
+	if mtRoot := os.Getenv("MOUNTTABLE_ROOT"); mtRoot != "" {
+		mounttableRoots = append(mounttableRoots, mtRoot)
+	}
 	msg := wsprConfig{
 		MounttableRoot: mounttableRoots,
 	}
diff --git a/services/wsprd/wspr/wspr.go b/services/wsprd/wspr/wspr.go
index 3a62cd6..bfebcb9 100644
--- a/services/wsprd/wspr/wspr.go
+++ b/services/wsprd/wspr/wspr.go
@@ -21,7 +21,6 @@
 	"fmt"
 	"io"
 	"log"
-	"net"
 	"net/http"
 	_ "net/http/pprof"
 	"sync"
@@ -51,6 +50,7 @@
 	tlsCert        *tls.Certificate
 	rt             veyron2.Runtime
 	logger         vlog.Logger
+	httpPort       int // HTTP port for WSPR to serve on. Port rather than address to discourage serving in a way that isn't local.
 	listenSpec     ipc.ListenSpec
 	identdEP       string
 	idManager      *identity.IDManager
@@ -93,12 +93,8 @@
 	// registered patterns, not just the URL with Path == "/".'
 	// (http://golang.org/pkg/net/http/#ServeMux)
 	http.Handle("/", http.NotFoundHandler())
-	_, port, err := net.SplitHostPort(ctx.listenSpec.Address)
-	if err != nil {
-		log.Fatal("Failed to extra port from %q", ctx.listenSpec.Address)
-	}
-	ctx.logger.VI(1).Infof("Listening on port %d.", port)
-	httpErr := http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), nil)
+	ctx.logger.VI(1).Infof("Listening at port %s.", ctx.httpPort)
+	httpErr := http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", ctx.httpPort), nil)
 	if httpErr != nil {
 		log.Fatalf("Failed to HTTP serve: %s", httpErr)
 	}
@@ -115,7 +111,7 @@
 }
 
 // Creates a new WebSocket Proxy object.
-func NewWSPR(listenSpec ipc.ListenSpec, identdEP string, opts ...veyron2.ROpt) *WSPR {
+func NewWSPR(httpPort int, listenSpec ipc.ListenSpec, identdEP string, opts ...veyron2.ROpt) *WSPR {
 	if listenSpec.Proxy == "" {
 		log.Fatalf("a veyron proxy must be set")
 	}
@@ -134,12 +130,14 @@
 		log.Fatalf("identity.NewIDManager failed: %s", err)
 	}
 
-	return &WSPR{listenSpec: listenSpec,
-		identdEP:  identdEP,
-		rt:        newrt,
-		logger:    newrt.Logger(),
-		idManager: idManager,
-		pipes:     map[*http.Request]*pipe{},
+	return &WSPR{
+		httpPort:   httpPort,
+		listenSpec: listenSpec,
+		identdEP:   identdEP,
+		rt:         newrt,
+		logger:     newrt.Logger(),
+		idManager:  idManager,
+		pipes:      map[*http.Request]*pipe{},
 	}
 }
 
diff --git a/services/wsprd/wspr_nacl/main_nacl.go b/services/wsprd/wspr_nacl/main_nacl.go
new file mode 100644
index 0000000..9696356
--- /dev/null
+++ b/services/wsprd/wspr_nacl/main_nacl.go
@@ -0,0 +1,160 @@
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"runtime/ppapi"
+	"syscall"
+
+	_ "veyron.io/veyron/veyron/runtimes/google/security"
+	"veyron.io/veyron/veyron/services/wsprd/wspr"
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/rt"
+)
+
+func main() {
+	ppapi.Init(newWsprInstance)
+}
+
+// WSPR instance represents an instance on a PPAPI client and receives callbacks from PPAPI to handle events.
+type wsprInstance struct {
+	ppapi.Instance
+}
+
+var _ ppapi.InstanceHandlers = wsprInstance{}
+
+func (inst wsprInstance) DidCreate(args map[string]string) bool {
+	fmt.Printf("Got to DidCreate")
+	return true
+}
+
+func (wsprInstance) DidDestroy() {
+	fmt.Printf("Got to DidDestroy()")
+}
+
+func (wsprInstance) DidChangeView(view ppapi.View) {
+	fmt.Printf("Got to DidChangeView(%v)", view)
+}
+
+func (wsprInstance) DidChangeFocus(has_focus bool) {
+	fmt.Printf("Got to DidChangeFocus(%v)", has_focus)
+}
+
+func (wsprInstance) HandleDocumentLoad(url_loader ppapi.Resource) bool {
+	fmt.Printf("Got to HandleDocumentLoad(%v)", url_loader)
+	return true
+}
+
+func (wsprInstance) HandleInputEvent(event ppapi.InputEvent) bool {
+	fmt.Printf("Got to HandleInputEvent(%v)", event)
+	return true
+}
+
+func (wsprInstance) Graphics3DContextLost() {
+	fmt.Printf("Got to Graphics3DContextLost()")
+}
+
+// StartWSPR handles starting WSPR.
+func (wsprInstance) StartWSPR(message ppapi.Var) {
+	identityContents, err := message.LookupStringValuedKey("identityContents")
+	if err != nil {
+		panic(err.Error())
+	}
+	file, err := ioutil.TempFile(os.TempDir(), "veyron_id")
+	if err != nil {
+		panic(err.Error())
+	}
+	_, err = file.WriteString(identityContents)
+	if err != nil {
+		panic(err.Error())
+	}
+	if err := file.Close(); err != nil {
+		panic(err.Error())
+	}
+	f, err := os.Open(file.Name())
+	if err != nil {
+		panic(err.Error())
+	}
+	b, err := ioutil.ReadAll(f)
+	if err != nil {
+		panic(err.Error())
+	}
+	fmt.Printf("IDENTITY: %s", string(b))
+	f.Close()
+	syscall.Setenv("VEYRON_IDENTITY", file.Name())
+
+	rt.Init()
+
+	veyronProxy, err := message.LookupStringValuedKey("proxy")
+	if err != nil {
+		panic(err.Error())
+	}
+	if veyronProxy == "" {
+		panic("Empty proxy")
+	}
+
+	mounttable, err := message.LookupStringValuedKey("mounttable")
+	if err != nil {
+		panic(err.Error())
+	}
+	syscall.Setenv("MOUNTTABLE_ROOT", mounttable)
+	syscall.Setenv("NAMESPACE_ROOT", mounttable)
+
+	identd, err := message.LookupStringValuedKey("identityd")
+	if err != nil {
+		panic(err.Error())
+	}
+
+	wsprHttpPort, err := message.LookupIntValuedKey("wsprHttpPort")
+	if err != nil {
+		panic(err.Error())
+	}
+
+	// TODO(cnicolaou,bprosnitz) Should we use the roaming profile?
+	// It uses flags. We should change that.
+	listenSpec := ipc.ListenSpec{
+		Proxy:    veyronProxy,
+		Protocol: "tcp",
+		Address:  ":0",
+	}
+
+	fmt.Printf("Starting WSPR with config: proxy=%q mounttable=%q identityd=%q port=%d", veyronProxy, mounttable, identd, wsprHttpPort)
+	proxy := wspr.NewWSPR(wsprHttpPort, listenSpec, identd)
+	go func() {
+		proxy.Run()
+	}()
+}
+
+// HandleMessage receives messages from Javascript and uses them to perform actions.
+// A message is of the form {"type": "typeName", "body": { stuff here }},
+// where the body is passed to the message handler.
+func (inst wsprInstance) HandleMessage(message ppapi.Var) {
+	type handlerType func(ppapi.Var)
+	handlerMap := map[string]handlerType{
+		"start": inst.StartWSPR,
+	}
+	fmt.Printf("Got to HandleMessage(%v)", message)
+	ty, err := message.LookupStringValuedKey("type")
+	if err != nil {
+		panic(err.Error())
+	}
+	h, ok := handlerMap[ty]
+	if !ok {
+		panic(fmt.Sprintf("No handler found for message type: %q", ty))
+	}
+	body, err := message.LookupKey("body")
+	if err != nil {
+		body = ppapi.VarFromString("INVALID")
+	}
+	h(body)
+	body.Release()
+}
+
+func (wsprInstance) MouseLockLost() {
+	fmt.Printf("Got to MouseLockLost()")
+}
+
+func newWsprInstance(inst ppapi.Instance) ppapi.InstanceHandlers {
+	return wsprInstance{Instance: inst}
+}
diff --git a/tools/identity/main_nacl.go b/tools/identity/main_nacl.go
new file mode 100644
index 0000000..2de5f27
--- /dev/null
+++ b/tools/identity/main_nacl.go
@@ -0,0 +1,3 @@
+package main
+
+const openCommand = "not-implemented"