flow/protocols/wsh_nacl: Add new wsh_nacl flow package protocol.

Also import the new protocols in the runtime factories.

Change-Id: I7e540b0e02951baddc3ff31ea101cd55cdbba608
diff --git a/runtime/factories/chrome/chrome.go b/runtime/factories/chrome/chrome.go
index 8245a77..c34ceae 100644
--- a/runtime/factories/chrome/chrome.go
+++ b/runtime/factories/chrome/chrome.go
@@ -15,10 +15,14 @@
 
 	"v.io/x/ref/lib/flags"
 	"v.io/x/ref/runtime/internal"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh_nacl"
 	"v.io/x/ref/runtime/internal/lib/websocket"
+	grt "v.io/x/ref/runtime/internal/rt"
+
+	// TODO(suharshs): Remove this after we switch to the flow protocols.
 	_ "v.io/x/ref/runtime/internal/rpc/protocols/ws"
 	_ "v.io/x/ref/runtime/internal/rpc/protocols/wsh_nacl"
-	grt "v.io/x/ref/runtime/internal/rt"
 )
 
 var commonFlags *flags.Flags
diff --git a/runtime/factories/fake/fake.go b/runtime/factories/fake/fake.go
index fa0e5fe..06d139b 100644
--- a/runtime/factories/fake/fake.go
+++ b/runtime/factories/fake/fake.go
@@ -16,6 +16,8 @@
 	"v.io/v23/rpc"
 
 	_ "v.io/x/ref/runtime/internal/flow/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh"
 	"v.io/x/ref/runtime/internal/lib/websocket"
 
 	// TODO(suharshs): Remove these once we switch to the flow protocols.
diff --git a/runtime/factories/gce/gce.go b/runtime/factories/gce/gce.go
index f99417c..584c823 100644
--- a/runtime/factories/gce/gce.go
+++ b/runtime/factories/gce/gce.go
@@ -21,6 +21,8 @@
 	"v.io/x/ref/lib/flags"
 	"v.io/x/ref/runtime/internal"
 	_ "v.io/x/ref/runtime/internal/flow/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh"
 	"v.io/x/ref/runtime/internal/gce"
 	"v.io/x/ref/runtime/internal/lib/appcycle"
 	"v.io/x/ref/runtime/internal/lib/websocket"
diff --git a/runtime/factories/generic/generic.go b/runtime/factories/generic/generic.go
index 651f710..61d58c6 100644
--- a/runtime/factories/generic/generic.go
+++ b/runtime/factories/generic/generic.go
@@ -16,6 +16,8 @@
 	"v.io/x/ref/lib/flags"
 	"v.io/x/ref/runtime/internal"
 	_ "v.io/x/ref/runtime/internal/flow/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh"
 	"v.io/x/ref/runtime/internal/lib/appcycle"
 	"v.io/x/ref/runtime/internal/lib/websocket"
 	grt "v.io/x/ref/runtime/internal/rt"
diff --git a/runtime/factories/roaming/roaming.go b/runtime/factories/roaming/roaming.go
index c139bfc..aca495d 100644
--- a/runtime/factories/roaming/roaming.go
+++ b/runtime/factories/roaming/roaming.go
@@ -30,6 +30,8 @@
 	"v.io/x/ref/lib/security/securityflag"
 	"v.io/x/ref/runtime/internal"
 	_ "v.io/x/ref/runtime/internal/flow/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh"
 	"v.io/x/ref/runtime/internal/lib/appcycle"
 	"v.io/x/ref/runtime/internal/lib/websocket"
 	irpc "v.io/x/ref/runtime/internal/rpc"
diff --git a/runtime/factories/static/static.go b/runtime/factories/static/static.go
index 9665d4d..9037f73 100644
--- a/runtime/factories/static/static.go
+++ b/runtime/factories/static/static.go
@@ -18,6 +18,8 @@
 	"v.io/x/ref/lib/security/securityflag"
 	"v.io/x/ref/runtime/internal"
 	_ "v.io/x/ref/runtime/internal/flow/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/flow/protocols/wsh"
 	"v.io/x/ref/runtime/internal/lib/appcycle"
 	"v.io/x/ref/runtime/internal/lib/websocket"
 
diff --git a/runtime/internal/flow/protocols/wsh_nacl/doc.go b/runtime/internal/flow/protocols/wsh_nacl/doc.go
new file mode 100644
index 0000000..ebeefda
--- /dev/null
+++ b/runtime/internal/flow/protocols/wsh_nacl/doc.go
@@ -0,0 +1,7 @@
+// 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 wsh_nacl registers the websocket 'hybrid' protocol for nacl
+// architectures. It will only be built if on the nacl architecture.
+package wsh_nacl
diff --git a/runtime/internal/flow/protocols/wsh_nacl/init.go b/runtime/internal/flow/protocols/wsh_nacl/init.go
new file mode 100644
index 0000000..f7874de
--- /dev/null
+++ b/runtime/internal/flow/protocols/wsh_nacl/init.go
@@ -0,0 +1,22 @@
+// 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.
+
+// +build nacl
+
+package wsh_nacl
+
+import (
+	"v.io/v23/flow"
+
+	websocket "v.io/x/ref/runtime/internal/lib/xwebsocket"
+)
+
+func init() {
+	// We limit wsh to ws since in general nacl does not allow direct access
+	// to TCP/UDP networking.
+	wshNaCl := websocket.WS{}
+	flow.RegisterProtocol("wsh", wshNaCl, "ws4", "ws6")
+	flow.RegisterProtocol("wsh4", wshNaCl, "ws4")
+	flow.RegisterProtocol("wsh6", wshNaCl, "ws6")
+}
diff --git a/runtime/internal/lib/xwebsocket/conn_nacl.go b/runtime/internal/lib/xwebsocket/conn_nacl.go
new file mode 100644
index 0000000..35cc5bb
--- /dev/null
+++ b/runtime/internal/lib/xwebsocket/conn_nacl.go
@@ -0,0 +1,92 @@
+// 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.
+
+// +build nacl
+
+package xwebsocket
+
+import (
+	"net"
+	"net/url"
+	"runtime/ppapi"
+	"sync"
+	"time"
+
+	"v.io/v23/context"
+	"v.io/v23/flow"
+)
+
+// Ppapi instance which must be set before the Dial is called.
+var PpapiInstance ppapi.Instance
+
+func WebsocketConn(address string, ws *ppapi.WebsocketConn) flow.Conn {
+	return &wrappedConn{
+		address: address,
+		ws:      ws,
+	}
+}
+
+type wrappedConn struct {
+	address   string
+	ws        *ppapi.WebsocketConn
+	readLock  sync.Mutex
+	writeLock sync.Mutex
+}
+
+func Dial(ctx *context.T, protocol, address string, timeout time.Duration) (flow.Conn, error) {
+	inst := PpapiInstance
+	u, err := url.Parse("ws://" + address)
+	if err != nil {
+		return nil, err
+	}
+
+	ws, err := inst.DialWebsocket(u.String())
+	if err != nil {
+		return nil, err
+	}
+	return WebsocketConn(address, ws), nil
+}
+
+func Resolve(ctx *context.T, protocol, address string) (string, string, error) {
+	return "ws", address, nil
+}
+
+func (c *wrappedConn) ReadMsg() ([]byte, error) {
+	defer c.readLock.Unlock()
+	c.readLock.Lock()
+	return c.ws.ReceiveMessage()
+}
+
+func (c *wrappedConn) WriteMsg(bufs ...[]byte) (int, error) {
+	defer c.writeLock.Unlock()
+	c.writeLock.Lock()
+	var b []byte
+	for _, buf := range bufs {
+		b = append(b, buf...)
+	}
+	if err := c.ws.SendMessage(b); err != nil {
+		return 0, err
+	}
+	return len(b), nil
+}
+
+func (c *wrappedConn) Close() error {
+	return c.ws.Close()
+}
+
+func (c *wrappedConn) LocalAddr() net.Addr {
+	return websocketAddr{s: c.address}
+}
+
+type websocketAddr struct {
+	s string
+}
+
+func (websocketAddr) Network() string {
+	return "ws"
+}
+
+func (w websocketAddr) String() string {
+	return w.s
+}
diff --git a/runtime/internal/lib/xwebsocket/errors.vdl b/runtime/internal/lib/xwebsocket/errors.vdl
index f80bdf6..5d27eb3 100644
--- a/runtime/internal/lib/xwebsocket/errors.vdl
+++ b/runtime/internal/lib/xwebsocket/errors.vdl
@@ -5,5 +5,6 @@
 package xwebsocket
 
 error (
-  ListenerClosed() {"en":"listener is already closed"}
+  ListenerClosed() {"en":"listener is already closed."}
+  ListenCalledInNaCl() {"en": "Listen cannot be called in NaCl code."}
 )
\ No newline at end of file
diff --git a/runtime/internal/lib/xwebsocket/errors.vdl.go b/runtime/internal/lib/xwebsocket/errors.vdl.go
index 47ee8b0..e436641 100644
--- a/runtime/internal/lib/xwebsocket/errors.vdl.go
+++ b/runtime/internal/lib/xwebsocket/errors.vdl.go
@@ -15,14 +15,21 @@
 )
 
 var (
-	ErrListenerClosed = verror.Register("v.io/x/ref/runtime/internal/lib/xwebsocket.ListenerClosed", verror.NoRetry, "{1:}{2:} listener is already closed")
+	ErrListenerClosed     = verror.Register("v.io/x/ref/runtime/internal/lib/xwebsocket.ListenerClosed", verror.NoRetry, "{1:}{2:} listener is already closed.")
+	ErrListenCalledInNaCl = verror.Register("v.io/x/ref/runtime/internal/lib/xwebsocket.ListenCalledInNaCl", verror.NoRetry, "{1:}{2:} Listen cannot be called in NaCl code.")
 )
 
 func init() {
-	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrListenerClosed.ID), "{1:}{2:} listener is already closed")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrListenerClosed.ID), "{1:}{2:} listener is already closed.")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrListenCalledInNaCl.ID), "{1:}{2:} Listen cannot be called in NaCl code.")
 }
 
 // NewErrListenerClosed returns an error with the ErrListenerClosed ID.
 func NewErrListenerClosed(ctx *context.T) error {
 	return verror.New(ErrListenerClosed, ctx)
 }
+
+// NewErrListenCalledInNaCl returns an error with the ErrListenCalledInNaCl ID.
+func NewErrListenCalledInNaCl(ctx *context.T) error {
+	return verror.New(ErrListenCalledInNaCl, ctx)
+}
diff --git a/runtime/internal/lib/xwebsocket/protocol.go b/runtime/internal/lib/xwebsocket/ws.go
similarity index 100%
rename from runtime/internal/lib/xwebsocket/protocol.go
rename to runtime/internal/lib/xwebsocket/ws.go
diff --git a/runtime/internal/lib/xwebsocket/hybrid.go b/runtime/internal/lib/xwebsocket/wsh.go
similarity index 98%
rename from runtime/internal/lib/xwebsocket/hybrid.go
rename to runtime/internal/lib/xwebsocket/wsh.go
index c69348a..b563ac6 100644
--- a/runtime/internal/lib/xwebsocket/hybrid.go
+++ b/runtime/internal/lib/xwebsocket/wsh.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !nacl
+
 package xwebsocket
 
 import (
diff --git a/runtime/internal/lib/xwebsocket/wsh_nacl.go b/runtime/internal/lib/xwebsocket/wsh_nacl.go
new file mode 100644
index 0000000..1e8e58d
--- /dev/null
+++ b/runtime/internal/lib/xwebsocket/wsh_nacl.go
@@ -0,0 +1,38 @@
+// 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.
+
+// +build nacl
+
+package xwebsocket
+
+import (
+	"net/url"
+	"time"
+
+	"v.io/v23/context"
+	"v.io/v23/flow"
+)
+
+type WS struct{}
+
+func (WS) Dial(ctx *context.T, protocol, address string, timeout time.Duration) (flow.Conn, error) {
+	inst := PpapiInstance
+	u, err := url.Parse("ws://" + address)
+	if err != nil {
+		return nil, err
+	}
+	ws, err := inst.DialWebsocket(u.String())
+	if err != nil {
+		return nil, err
+	}
+	return WebsocketConn(address, ws), nil
+}
+
+func (WS) Resolve(ctx *context.T, protocol, address string) (string, string, error) {
+	return "ws", address, nil
+}
+
+func (WS) Listen(ctx *context.T, protocol, address string) (flow.Listener, error) {
+	return nil, NewErrListenCalledInNaCl(ctx)
+}