veyron2/naming: add a field to endpoints to reflect whether they serve a mounttable or not.
Change-Id: I16813298daa96c7f4db258498847b85cb1e745ed
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 610e2a6..ddefad2 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -152,6 +152,8 @@
return nil, err
}
}
+ // TODO(cnicolaou): pass ServesMountTableOpt to streamMgr.Listen so that
+ // it can more cleanly set the IsMountTable bit in the endpoint.
ln, ep, err := s.streamMgr.Listen(protocol, address, s.listenerOpts...)
if err != nil {
vlog.Errorf("ipc: Listen on %v %v failed: %v", protocol, address, err)
@@ -197,18 +199,18 @@
// Each flow is served from its own goroutine.
s.active.Add(1)
if protocol == inaming.Network {
- go func(ln stream.Listener, ep naming.Endpoint, proxy string) {
+ go func(ln stream.Listener, ep *inaming.Endpoint, proxy string) {
s.proxyListenLoop(ln, ep, proxy)
s.active.Done()
- }(ln, ep, proxyName)
+ }(ln, iep, proxyName)
} else {
go func(ln stream.Listener, ep naming.Endpoint) {
s.listenLoop(ln, ep)
s.active.Done()
- }(ln, ep)
+ }(ln, iep)
}
s.Unlock()
- s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+ s.publisher.AddServer(s.publishEP(iep, s.servesMountTable), s.servesMountTable)
return ep, nil
}
@@ -221,7 +223,6 @@
if !ok {
return nil, nil, fmt.Errorf("failed translating internal endpoint data types")
}
-
switch iep.Protocol {
case "tcp", "tcp4", "tcp6":
host, port, err := net.SplitHostPort(iep.Address)
@@ -338,41 +339,48 @@
vlog.Errorf("ipc: Listen on %v %v failed: %v", protocol, address, err)
return nil, err
}
+ ipep, ok := pep.(*inaming.Endpoint)
+ if !ok {
+ return nil, fmt.Errorf("failed translating internal endpoint data types")
+ }
// We have a goroutine for listening on proxy connections.
s.active.Add(1)
- go func(ln stream.Listener, ep naming.Endpoint, proxy string) {
+ go func(ln stream.Listener, ep *inaming.Endpoint, proxy string) {
s.proxyListenLoop(ln, ep, proxy)
s.active.Done()
- }(pln, pep, listenSpec.Proxy)
+ }(pln, ipep, listenSpec.Proxy)
s.listeners[pln] = nil
- s.publisher.AddServer(s.publishEP(pep), s.servesMountTable)
+ // TODO(cnicolaou,p): AddServer no longer needs to take the
+ // servesMountTable bool since it can be extracted from the endpoint.
+ s.publisher.AddServer(s.publishEP(ipep, s.servesMountTable), s.servesMountTable)
} else {
- s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+ s.publisher.AddServer(s.publishEP(ep, s.servesMountTable), s.servesMountTable)
}
s.Unlock()
return ep, nil
}
-func (s *server) publishEP(ep naming.Endpoint) string {
+func (s *server) publishEP(ep *inaming.Endpoint, servesMountTable bool) string {
var name string
if !s.servesMountTable {
// Make sure that client MountTable code doesn't try and
// ResolveStep past this final address.
name = "//"
}
+ ep.IsMountTable = servesMountTable
return naming.JoinAddressName(ep.String(), name)
}
-func (s *server) proxyListenLoop(ln stream.Listener, ep naming.Endpoint, proxy string) {
+func (s *server) proxyListenLoop(ln stream.Listener, iep *inaming.Endpoint, proxy string) {
const (
min = 5 * time.Millisecond
max = 5 * time.Minute
)
for {
- s.listenLoop(ln, ep)
+ s.listenLoop(ln, iep)
// The listener is done, so:
// (1) Unpublish its name
- s.publisher.RemoveServer(s.publishEP(ep))
+ s.publisher.RemoveServer(s.publishEP(iep, s.servesMountTable))
// (2) Reconnect to the proxy unless the server has been stopped
backoff := min
ln = nil
@@ -384,9 +392,17 @@
vlog.VI(1).Infof("Failed to resolve proxy %q (%v), will retry in %v", proxy, err, backoff)
break
}
+ var ep naming.Endpoint
ln, ep, err = s.streamMgr.Listen(inaming.Network, resolved, s.listenerOpts...)
if err == nil {
- vlog.VI(1).Infof("Reconnected to proxy at %q listener: (%v, %v)", proxy, ln, ep)
+ var ok bool
+ iep, ok = ep.(*inaming.Endpoint)
+ if !ok {
+ vlog.Errorf("failed translating internal endpoint data types")
+ ln = nil
+ continue
+ }
+ vlog.VI(1).Infof("Reconnected to proxy at %q listener: (%v, %v)", proxy, ln, iep)
break
}
if backoff = backoff * 2; backoff > max {
@@ -397,8 +413,13 @@
return
}
}
+ // TODO(cnicolaou,ashankar): this won't work when we are both
+ // proxying and publishing locally, which is the common case.
+ // listenLoop, dhcpLoop and the original publish are all publishing
+ // addresses to the same name, but the client is not smart enough
+ // to choose sensibly between them.
// (3) reconnected, publish new address
- s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+ s.publisher.AddServer(s.publishEP(iep, s.servesMountTable), s.servesMountTable)
s.Lock()
s.listeners[ln] = nil
s.Unlock()
@@ -438,7 +459,7 @@
for _, a := range addrs {
if ip := netstate.AsIP(a); ip != nil {
dhcpl.ep.Address = net.JoinHostPort(ip.String(), dhcpl.port)
- fn(s.publishEP(dhcpl.ep))
+ fn(s.publishEP(dhcpl.ep, s.servesMountTable))
}
}
}
@@ -459,6 +480,11 @@
s.Unlock()
return
}
+ // TODO(cnicolaou,ashankar): this won't work when we are both
+ // proxying and publishing locally, which is the common case.
+ // listenLoop, dhcpLoop and the original publish are all publishing
+ // addresses to the same name, but the client is not smart enough
+ // to choose sensibly between them.
publisher := s.publisher
s.Unlock()
switch setting.Name() {
diff --git a/runtimes/google/ipc/stream/vc/vc_test.go b/runtimes/google/ipc/stream/vc/vc_test.go
index 086cc23..c469fe6 100644
--- a/runtimes/google/ipc/stream/vc/vc_test.go
+++ b/runtimes/google/ipc/stream/vc/vc_test.go
@@ -446,6 +446,8 @@
type endpoint naming.RoutingID
func (e endpoint) Network() string { return "test" }
+func (e endpoint) VersionedString(int) string { return e.String() }
func (e endpoint) String() string { return naming.RoutingID(e).String() }
func (e endpoint) RoutingID() naming.RoutingID { return naming.RoutingID(e) }
func (e endpoint) Addr() net.Addr { return nil }
+func (e endpoint) ServesMountTable() bool { return false }
diff --git a/runtimes/google/naming/endpoint.go b/runtimes/google/naming/endpoint.go
index 48979b5..e2fefd9 100644
--- a/runtimes/google/naming/endpoint.go
+++ b/runtimes/google/naming/endpoint.go
@@ -29,6 +29,7 @@
RID naming.RoutingID
MinIPCVersion version.IPCVersion
MaxIPCVersion version.IPCVersion
+ IsMountTable bool
}
// NewEndpoint creates a new endpoint from a string as per naming.NewEndpoint
@@ -54,6 +55,8 @@
err = ep.parseV1(parts)
case 2:
err = ep.parseV2(parts)
+ case 3:
+ err = ep.parseV3(parts)
default:
err = errInvalidEndpointString
}
@@ -112,6 +115,20 @@
return strconv.FormatUint(uint64(v), 10)
}
+func parseMountTableFlag(input string) (bool, error) {
+ if len(input) == 1 {
+ switch f := input[0]; f {
+ case 'm':
+ return true, nil
+ case 's':
+ return false, nil
+ default:
+ return false, fmt.Errorf("%c is not one of 'm' or 's'", f)
+ }
+ }
+ return false, fmt.Errorf("flag is either missing or too long")
+}
+
func (ep *Endpoint) parseV2(parts []string) error {
var err error
if len(parts) != 6 {
@@ -129,6 +146,20 @@
return nil
}
+func (ep *Endpoint) parseV3(parts []string) error {
+ var err error
+ if len(parts) != 7 {
+ return errInvalidEndpointString
+ }
+ if err = ep.parseV2(parts[:6]); err != nil {
+ return err
+ }
+ if ep.IsMountTable, err = parseMountTableFlag(parts[6]); err != nil {
+ return fmt.Errorf("invalid mount table flag: %v", err)
+ }
+ return nil
+}
+
func (ep *Endpoint) RoutingID() naming.RoutingID {
//nologcall
return ep.RID
@@ -137,19 +168,46 @@
//nologcall
return Network
}
+
+var defaultVersion = 2
+
+func (ep *Endpoint) VersionedString(version int) string {
+ switch version {
+ default:
+ return ep.VersionedString(defaultVersion)
+ case 1:
+ return fmt.Sprintf("@1@%s@%s@@", ep.Protocol, ep.Address)
+ case 2:
+ return fmt.Sprintf("@2@%s@%s@%s@%s@%s@@",
+ ep.Protocol, ep.Address, ep.RID,
+ printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
+ case 3:
+ mt := "s"
+ if ep.IsMountTable {
+ mt = "m"
+ }
+ return fmt.Sprintf("@3@%s@%s@%s@%s@%s@%s@@",
+ ep.Protocol, ep.Address, ep.RID,
+ printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion),
+ mt)
+ }
+}
+
func (ep *Endpoint) String() string {
//nologcall
- return fmt.Sprintf("%s2@%s@%s@%s@%s@%s@@",
- separator, ep.Protocol, ep.Address, ep.RID,
- printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
+ return ep.VersionedString(defaultVersion)
}
-func (ep *Endpoint) version() int { return 2 }
func (ep *Endpoint) Addr() net.Addr {
//nologcall
return &addr{network: ep.Protocol, address: ep.Address}
}
+func (ep *Endpoint) ServesMountTable() bool {
+ //nologcall
+ return true
+}
+
type addr struct {
network, address string
}
diff --git a/runtimes/google/naming/endpoint_test.go b/runtimes/google/naming/endpoint_test.go
index f0d036b..00135c5 100644
--- a/runtimes/google/naming/endpoint_test.go
+++ b/runtimes/google/naming/endpoint_test.go
@@ -29,6 +29,14 @@
MinIPCVersion: 2,
MaxIPCVersion: 3,
}
+ v3 := &Endpoint{
+ Protocol: "tcp",
+ Address: "batman.com:2345",
+ RID: naming.FixedRoutingID(0x0),
+ MinIPCVersion: 2,
+ MaxIPCVersion: 3,
+ IsMountTable: true,
+ }
testcasesA := []struct {
endpoint naming.Endpoint
@@ -53,10 +61,13 @@
String string
Input string
min, max version.IPCVersion
+ servesMT bool
}{
- {v1, "@2@tcp@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion},
- {v2, "@2@tcp@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10},
- {v2hp, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3},
+ {v1, "@2@tcp@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion, false},
+ {v2, "@2@tcp@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10, false},
+ {v2hp, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, false},
+ // the v3 format is ignored unless explicitly enabled.
+ {v3, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, true},
}
for _, test := range testcasesB {
@@ -71,7 +82,8 @@
ep, err = NewEndpoint(str)
} else {
ep, err = NewEndpoint(naming.FormatEndpoint("tcp", str,
- version.IPCVersionRange{test.min, test.max}))
+ version.IPCVersionRange{test.min, test.max},
+ naming.ServesMountTableOpt(test.servesMT)))
}
if err != nil {
t.Errorf("Endpoint(%q) failed with %v", str, err)
@@ -81,6 +93,25 @@
t.Errorf("Got endpoint %T = %#v, want %T = %#v for string %q", ep, ep, test.Endpoint, test.Endpoint, str)
}
}
+
+ // Enable V3 endpoints.
+ defaultVersion = 3
+ for _, c := range []struct {
+ servesMT bool
+ str string
+ }{
+ {true, "@3@tcp@a:10@00000000000000000000000000000000@1@3@m@@"},
+ {false, "@3@tcp@a:10@00000000000000000000000000000000@1@3@s@@"},
+ } {
+ ep, _ := NewEndpoint(naming.FormatEndpoint("tcp", "a:10",
+ version.IPCVersionRange{1, 3},
+ naming.ServesMountTableOpt(c.servesMT)))
+ if got, want := ep.String(), c.str; got != want {
+ t.Errorf("got: %s, want: %s", got, want)
+ }
+ }
+ // Disable V3 endpoints.
+ defaultVersion = 2
}
type endpointTest struct {