Add support for handling "unknown" protocols.

There is no longer a default protocol for Endpoints.  Endpoints that do
not have a protocol will have Endpoint.protocol == "".

There is a new method to the stream registry called
"RegisterUnknownProtocol", which is used to register a Dialer and
Listener for endpoints with no protocol.

All the profiles have been updated to use "wsh" for unknown protocols.

The endpoint sorter in sort_endpoints.go will include endpoints
with unknown protocols last.

MultiPart: 1/3

Change-Id: If0771153fc96bffc8dbc79956c8f12f320696343
diff --git a/profiles/chrome/chromeinit.go b/profiles/chrome/chromeinit.go
index 6ec957d..804ae73 100644
--- a/profiles/chrome/chromeinit.go
+++ b/profiles/chrome/chromeinit.go
@@ -5,13 +5,16 @@
 import (
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
+	"v.io/core/veyron2/ipc/stream"
 
+	"v.io/core/veyron/lib/websocket"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/ws"
 	grt "v.io/core/veyron/runtimes/google/rt"
 )
 
 func init() {
 	veyron2.RegisterProfileInit(Init)
+	stream.RegisterUnknownProtocol("wsh", websocket.Dial, websocket.Listener)
 }
 
 func Init(ctx *context.T) (veyron2.RuntimeX, *context.T, veyron2.Shutdown, error) {
diff --git a/profiles/gce/initx.go b/profiles/gce/initx.go
index 45d9b23..b344955 100644
--- a/profiles/gce/initx.go
+++ b/profiles/gce/initx.go
@@ -13,11 +13,13 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/ipc/stream"
 	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/lib/appcycle"
 	"v.io/core/veyron/lib/flags"
 	"v.io/core/veyron/lib/netstate"
+	"v.io/core/veyron/lib/websocket"
 	"v.io/core/veyron/profiles/internal/gce"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/tcp"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/ws"
@@ -32,6 +34,7 @@
 func init() {
 	commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Listen)
 	veyron2.RegisterProfileInit(Init)
+	stream.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
 }
 
 func Init(ctx *context.T) (veyron2.RuntimeX, *context.T, veyron2.Shutdown, error) {
diff --git a/profiles/genericinit.go b/profiles/genericinit.go
index 257974a..95f28a5 100644
--- a/profiles/genericinit.go
+++ b/profiles/genericinit.go
@@ -4,8 +4,10 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/ipc/stream"
 
 	"v.io/core/veyron/lib/appcycle"
+	"v.io/core/veyron/lib/websocket"
 	"v.io/core/veyron/profiles/internal"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/tcp"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/ws"
@@ -15,6 +17,7 @@
 
 func init() {
 	veyron2.RegisterProfileInit(Init)
+	stream.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
 }
 
 func Init(ctx *context.T) (veyron2.RuntimeX, *context.T, veyron2.Shutdown, error) {
diff --git a/profiles/roaming/roaminginit.go b/profiles/roaming/roaminginit.go
index 8dbe076..3d5bfe0 100644
--- a/profiles/roaming/roaminginit.go
+++ b/profiles/roaming/roaminginit.go
@@ -18,12 +18,14 @@
 	"v.io/core/veyron2/config"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/ipc/stream"
 	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/lib/appcycle"
 	"v.io/core/veyron/lib/flags"
 	"v.io/core/veyron/lib/netconfig"
 	"v.io/core/veyron/lib/netstate"
+	"v.io/core/veyron/lib/websocket"
 	"v.io/core/veyron/profiles/internal"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/tcp"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/ws"
@@ -46,6 +48,7 @@
 func init() {
 	commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Listen)
 	veyron2.RegisterProfileInit(Init)
+	stream.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
 }
 
 func Init(ctx *context.T) (veyron2.RuntimeX, *context.T, veyron2.Shutdown, error) {
diff --git a/profiles/static/staticinit.go b/profiles/static/staticinit.go
index 4f84141..a28ddab 100644
--- a/profiles/static/staticinit.go
+++ b/profiles/static/staticinit.go
@@ -7,11 +7,13 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/ipc/stream"
 	"v.io/core/veyron2/vlog"
 
 	"v.io/core/veyron/lib/appcycle"
 	"v.io/core/veyron/lib/flags"
 	"v.io/core/veyron/lib/netstate"
+	"v.io/core/veyron/lib/websocket"
 	"v.io/core/veyron/profiles/internal"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/tcp"
 	_ "v.io/core/veyron/runtimes/google/ipc/protocols/ws"
@@ -30,6 +32,7 @@
 func init() {
 	commonFlags = flags.CreateAndRegister(flag.CommandLine, flags.Listen)
 	veyron2.RegisterProfileInit(Init)
+	stream.RegisterUnknownProtocol("wsh", websocket.HybridDial, websocket.HybridListener)
 }
 
 func Init(ctx *context.T) (veyron2.RuntimeX, *context.T, veyron2.Shutdown, error) {
diff --git a/runtimes/google/ipc/sort_endpoints.go b/runtimes/google/ipc/sort_endpoints.go
index 4036825..58a6d57 100644
--- a/runtimes/google/ipc/sort_endpoints.go
+++ b/runtimes/google/ipc/sort_endpoints.go
@@ -81,9 +81,18 @@
 	byProtocol := make(map[string][]*serverEndpoint)
 	matched := false
 	for _, ep := range eps {
+		if ep.iep.Protocol == naming.UnknownProtocol {
+			byProtocol[naming.UnknownProtocol] = append(byProtocol[naming.UnknownProtocol], ep)
+			matched = true
+			break
+		}
 		found := false
 		for _, p := range protocols {
-			if ep.iep.Protocol == p || (p == "tcp" && strings.HasPrefix(ep.iep.Protocol, "tcp")) {
+			if ep.iep.Protocol == p ||
+				(p == "tcp" && strings.HasPrefix(ep.iep.Protocol, "tcp")) ||
+				(p == "wsh" && strings.HasPrefix(ep.iep.Protocol, "wsh")) ||
+				// Can't use strings.HasPrefix below because of "wsh" has the prefix "ws" but is a different protocol.
+				(p == "ws" && (ep.iep.Protocol == "ws4" || ep.iep.Protocol == "ws6")) {
 				byProtocol[p] = append(byProtocol[p], ep)
 				found = true
 				matched = true
@@ -199,6 +208,9 @@
 		preferredProtocolOrder = protocols
 	}
 
+	// Add unknown protocol to the order last.
+	preferredProtocolOrder = append(preferredProtocolOrder, naming.UnknownProtocol)
+
 	// put the server endpoints into per-protocol lists
 	matched, byProtocol := sortByProtocol(compatible, preferredProtocolOrder)
 	if !defaultOrdering && !matched {
diff --git a/runtimes/google/naming/endpoint.go b/runtimes/google/naming/endpoint.go
index b5f20a8..5390008 100644
--- a/runtimes/google/naming/endpoint.go
+++ b/runtimes/google/naming/endpoint.go
@@ -71,7 +71,7 @@
 	if _, _, err := net.SplitHostPort(input); err != nil {
 		return errInvalidEndpointString
 	}
-	ep.Protocol = "tcp"
+	ep.Protocol = naming.UnknownProtocol
 	ep.Address = input
 	ep.RID = naming.NullRoutingID
 
@@ -85,7 +85,7 @@
 
 	ep.Protocol = parts[1]
 	if len(ep.Protocol) == 0 {
-		ep.Protocol = "tcp"
+		ep.Protocol = naming.UnknownProtocol
 	}
 
 	ep.Address = parts[2]
diff --git a/runtimes/google/naming/endpoint_test.go b/runtimes/google/naming/endpoint_test.go
index 744d344..c1e1bf7 100644
--- a/runtimes/google/naming/endpoint_test.go
+++ b/runtimes/google/naming/endpoint_test.go
@@ -11,13 +11,13 @@
 
 func TestEndpoint(t *testing.T) {
 	v1 := &Endpoint{
-		Protocol:     "tcp",
+		Protocol:     naming.UnknownProtocol,
 		Address:      "batman.com:1234",
 		RID:          naming.FixedRoutingID(0xdabbad00),
 		IsMountTable: true,
 	}
 	v2 := &Endpoint{
-		Protocol:      "tcp",
+		Protocol:      naming.UnknownProtocol,
 		Address:       "batman.com:2345",
 		RID:           naming.FixedRoutingID(0xdabbad00),
 		MinIPCVersion: 1,
@@ -25,7 +25,7 @@
 		IsMountTable:  true,
 	}
 	v2hp := &Endpoint{
-		Protocol:      "tcp",
+		Protocol:      naming.UnknownProtocol,
 		Address:       "batman.com:2345",
 		RID:           naming.FixedRoutingID(0x0),
 		MinIPCVersion: 2,
@@ -33,7 +33,7 @@
 		IsMountTable:  true,
 	}
 	v3s := &Endpoint{
-		Protocol:      "tcp",
+		Protocol:      naming.UnknownProtocol,
 		Address:       "batman.com:2345",
 		RID:           naming.FixedRoutingID(0x0),
 		MinIPCVersion: 2,
@@ -41,13 +41,29 @@
 		IsMountTable:  false,
 	}
 	v3m := &Endpoint{
-		Protocol:      "tcp",
+		Protocol:      naming.UnknownProtocol,
 		Address:       "batman.com:2345",
 		RID:           naming.FixedRoutingID(0xdabbad00),
 		MinIPCVersion: 2,
 		MaxIPCVersion: 3,
 		IsMountTable:  true,
 	}
+	v3tcp := &Endpoint{
+		Protocol:      "tcp",
+		Address:       "batman.com:2345",
+		RID:           naming.FixedRoutingID(0x0),
+		MinIPCVersion: 2,
+		MaxIPCVersion: 3,
+		IsMountTable:  false,
+	}
+	v3ws6 := &Endpoint{
+		Protocol:      "ws6",
+		Address:       "batman.com:2345",
+		RID:           naming.FixedRoutingID(0x0),
+		MinIPCVersion: 2,
+		MaxIPCVersion: 3,
+		IsMountTable:  false,
+	}
 
 	testcasesA := []struct {
 		endpoint naming.Endpoint
@@ -59,9 +75,6 @@
 	}
 	for _, test := range testcasesA {
 		addr := test.endpoint.Addr()
-		if addr.Network() != "tcp" {
-			t.Errorf("unexpected network %q", addr.Network())
-		}
 		if addr.String() != test.address {
 			t.Errorf("unexpected address %q, not %q", addr.String(), test.address)
 		}
@@ -76,8 +89,10 @@
 		min, max version.IPCVersion
 		servesMT bool
 	}{
-		{v3s, "@3@tcp@batman.com:2345@00000000000000000000000000000000@2@3@s@@", "", 2, 3, false},
-		{v3m, "@3@tcp@batman.com:2345@000000000000000000000000dabbad00@2@3@m@@", "", 2, 3, true},
+		{v3s, "@3@@batman.com:2345@00000000000000000000000000000000@2@3@s@@", "", 2, 3, false},
+		{v3m, "@3@@batman.com:2345@000000000000000000000000dabbad00@2@3@m@@", "", 2, 3, true},
+		{v3tcp, "@3@tcp@batman.com:2345@00000000000000000000000000000000@2@3@s@@", "", 2, 3, false},
+		{v3ws6, "@3@ws6@batman.com:2345@00000000000000000000000000000000@2@3@s@@", "", 2, 3, false},
 	}
 
 	for _, test := range testcasesC {
@@ -113,9 +128,9 @@
 		min, max version.IPCVersion
 		servesMT bool
 	}{
-		{v1, "@2@tcp@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion, true},
-		{v2, "@2@tcp@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10, true},
-		{v2hp, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, true},
+		{v1, "@2@@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion, true},
+		{v2, "@2@@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10, true},
+		{v2hp, "@2@@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, true},
 	}
 
 	for _, test := range testcasesB {
@@ -129,7 +144,7 @@
 			str = test.String
 			ep, err = NewEndpoint(str)
 		} else {
-			ep, err = NewEndpoint(naming.FormatEndpoint("tcp", str,
+			ep, err = NewEndpoint(naming.FormatEndpoint(naming.UnknownProtocol, str,
 				version.IPCVersionRange{test.min, test.max},
 				naming.ServesMountTableOpt(test.servesMT)))
 		}
@@ -153,15 +168,15 @@
 	testcases := []endpointTest{
 		{"@1@tcp@batman@@@", "@3@tcp@batman@00000000000000000000000000000000@@@m@@", nil},
 		{"@2@tcp@robin@@@@@", "@3@tcp@robin@00000000000000000000000000000000@@@m@@", nil},
-		{"@1@@@@@", "@3@tcp@:0@00000000000000000000000000000000@@@m@@", nil},
-		{"@2@@@@@@@", "@3@tcp@:0@00000000000000000000000000000000@@@m@@", nil},
+		{"@1@@@@@", "@3@@:0@00000000000000000000000000000000@@@m@@", nil},
+		{"@2@@@@@@@", "@3@@:0@00000000000000000000000000000000@@@m@@", nil},
 		{"@1@tcp@batman:12@@@", "@3@tcp@batman:12@00000000000000000000000000000000@@@m@@", nil},
-		{"@host:10@@", "@3@tcp@host:10@00000000000000000000000000000000@@@m@@", nil},
+		{"@host:10@@", "@3@@host:10@00000000000000000000000000000000@@@m@@", nil},
 		{"@2@tcp@foo:12@@9@@@", "@3@tcp@foo:12@00000000000000000000000000000000@9@@m@@", nil},
 		{"@2@tcp@foo:12@@@4@@", "@3@tcp@foo:12@00000000000000000000000000000000@@4@m@@", nil},
 		{"@2@tcp@foo:12@@2@4@@", "@3@tcp@foo:12@00000000000000000000000000000000@2@4@m@@", nil},
-		{"@3@@host:11@@@@m@@", "@3@tcp@host:11@00000000000000000000000000000000@@@m@@", nil},
-		{"@3@@host:12@@@@@@", "@3@tcp@host:12@00000000000000000000000000000000@@@m@@", nil},
+		{"@3@@host:11@@@@m@@", "@3@@host:11@00000000000000000000000000000000@@@m@@", nil},
+		{"@3@@host:12@@@@@@", "@3@@host:12@00000000000000000000000000000000@@@m@@", nil},
 	}
 	runEndpointTests(t, testcases)
 }
@@ -188,8 +203,8 @@
 
 func TestHostPortEndpoint(t *testing.T) {
 	testcases := []endpointTest{
-		{"localhost:10", "@3@tcp@localhost:10@00000000000000000000000000000000@@@m@@", nil},
-		{"localhost:", "@3@tcp@localhost:@00000000000000000000000000000000@@@m@@", nil},
+		{"localhost:10", "@3@@localhost:10@00000000000000000000000000000000@@@m@@", nil},
+		{"localhost:", "@3@@localhost:@00000000000000000000000000000000@@@m@@", nil},
 		{"localhost", "", errInvalidEndpointString},
 	}
 	runEndpointTests(t, testcases)