Merge "runtime/internal/flow/conn: Increment next flowID by 2."
diff --git a/runtime/internal/flow/conn/conn.go b/runtime/internal/flow/conn/conn.go
index 8baf303..2c3ee15 100644
--- a/runtime/internal/flow/conn/conn.go
+++ b/runtime/internal/flow/conn/conn.go
@@ -207,7 +207,7 @@
 		return nil, NewErrConnectionClosed(ctx)
 	}
 	id := c.nextFid
-	c.nextFid++
+	c.nextFid += 2
 	return c.newFlowLocked(ctx, id, bkey, dkey, true, false), nil
 }
 
@@ -381,6 +381,10 @@
 
 	case *message.OpenFlow:
 		c.mu.Lock()
+		if c.nextFid%2 == msg.ID%2 {
+			c.mu.Unlock()
+			return NewErrInvalidPeerFlow(ctx)
+		}
 		if c.handler == nil {
 			c.mu.Unlock()
 			return NewErrUnexpectedMsg(ctx, "openFlow")
diff --git a/runtime/internal/flow/conn/errors.vdl b/runtime/internal/flow/conn/errors.vdl
index dcd8c02..7538acb 100644
--- a/runtime/internal/flow/conn/errors.vdl
+++ b/runtime/internal/flow/conn/errors.vdl
@@ -29,4 +29,5 @@
   UpdatingNilFlowHandler() {"en": "nil flowHandler cannot be updated to non-nil value."}
   BlessingsNotBound() {"en": "blessings not bound to connection remote public key"}
   NoBlessingsForPeer(peerNames []string, rejected []security.RejectedBlessing, err error) {"en": "no blessings tagged for peer {peerNames}, rejected:{rejected}{:err}"}
+  InvalidPeerFlow() {"en": "peer has chosen flow id from local domain."}
 )
diff --git a/runtime/internal/flow/conn/errors.vdl.go b/runtime/internal/flow/conn/errors.vdl.go
index f4d3110..047fd13 100644
--- a/runtime/internal/flow/conn/errors.vdl.go
+++ b/runtime/internal/flow/conn/errors.vdl.go
@@ -34,6 +34,7 @@
 	ErrUpdatingNilFlowHandler   = verror.Register("v.io/x/ref/runtime/internal/flow/conn.UpdatingNilFlowHandler", verror.NoRetry, "{1:}{2:} nil flowHandler cannot be updated to non-nil value.")
 	ErrBlessingsNotBound        = verror.Register("v.io/x/ref/runtime/internal/flow/conn.BlessingsNotBound", verror.NoRetry, "{1:}{2:} blessings not bound to connection remote public key")
 	ErrNoBlessingsForPeer       = verror.Register("v.io/x/ref/runtime/internal/flow/conn.NoBlessingsForPeer", verror.NoRetry, "{1:}{2:} no blessings tagged for peer {3}, rejected:{4}{:5}")
+	ErrInvalidPeerFlow          = verror.Register("v.io/x/ref/runtime/internal/flow/conn.InvalidPeerFlow", verror.NoRetry, "{1:}{2:} peer has chosen flow id from local domain.")
 )
 
 func init() {
@@ -53,6 +54,7 @@
 	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrUpdatingNilFlowHandler.ID), "{1:}{2:} nil flowHandler cannot be updated to non-nil value.")
 	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrBlessingsNotBound.ID), "{1:}{2:} blessings not bound to connection remote public key")
 	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrNoBlessingsForPeer.ID), "{1:}{2:} no blessings tagged for peer {3}, rejected:{4}{:5}")
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrInvalidPeerFlow.ID), "{1:}{2:} peer has chosen flow id from local domain.")
 }
 
 // NewErrMissingSetupOption returns an error with the ErrMissingSetupOption ID.
@@ -134,3 +136,8 @@
 func NewErrNoBlessingsForPeer(ctx *context.T, peerNames []string, rejected []security.RejectedBlessing, err error) error {
 	return verror.New(ErrNoBlessingsForPeer, ctx, peerNames, rejected, err)
 }
+
+// NewErrInvalidPeerFlow returns an error with the ErrInvalidPeerFlow ID.
+func NewErrInvalidPeerFlow(ctx *context.T) error {
+	return verror.New(ErrInvalidPeerFlow, ctx)
+}