Merge "services/device/devicex: fix devicex for Darwin multi-user mode"
diff --git a/runtime/internal/flow/manager/errors.vdl b/runtime/internal/flow/manager/errors.vdl
new file mode 100644
index 0000000..ef03f4e
--- /dev/null
+++ b/runtime/internal/flow/manager/errors.vdl
@@ -0,0 +1,14 @@
+// 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 manager
+
+// These messages are constructed so as to avoid embedding a component/method name
+// and are thus more suitable for inclusion in other verrors.
+// This practice of omitting {1}{2} should be used throughout the flow implementations
+// since all of their errors are intended to be used as arguments to higher level errors.
+// TODO(suharshs,toddw): Allow skipping of {1}{2} in vdl generated errors.
+error (
+  LargerThan3ByteUInt() {"en":"integer too large to represent in 3 bytes"}
+)
\ No newline at end of file
diff --git a/runtime/internal/flow/manager/errors.vdl.go b/runtime/internal/flow/manager/errors.vdl.go
new file mode 100644
index 0000000..2029486
--- /dev/null
+++ b/runtime/internal/flow/manager/errors.vdl.go
@@ -0,0 +1,28 @@
+// 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.
+
+// This file was auto-generated by the vanadium vdl tool.
+// Source: errors.vdl
+
+package manager
+
+import (
+	// VDL system imports
+	"v.io/v23/context"
+	"v.io/v23/i18n"
+	"v.io/v23/verror"
+)
+
+var (
+	ErrLargerThan3ByteUInt = verror.Register("v.io/x/ref/runtime/internal/flow/manager.LargerThan3ByteUInt", verror.NoRetry, "{1:}{2:} integer too large to represent in 3 bytes")
+)
+
+func init() {
+	i18n.Cat().SetWithBase(i18n.LangID("en"), i18n.MsgID(ErrLargerThan3ByteUInt.ID), "{1:}{2:} integer too large to represent in 3 bytes")
+}
+
+// NewErrLargerThan3ByteUInt returns an error with the ErrLargerThan3ByteUInt ID.
+func NewErrLargerThan3ByteUInt(ctx *context.T) error {
+	return verror.New(ErrLargerThan3ByteUInt, ctx)
+}
diff --git a/runtime/internal/flow/manager/framer.go b/runtime/internal/flow/manager/framer.go
new file mode 100644
index 0000000..6e2a991
--- /dev/null
+++ b/runtime/internal/flow/manager/framer.go
@@ -0,0 +1,79 @@
+// 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 manager
+
+import (
+	"io"
+
+	"v.io/v23/flow"
+)
+
+// framer is a wrapper of io.ReadWriter that adds framing to a net.Conn
+// and implements flow.MsgReadWriter.
+type framer struct {
+	io.ReadWriter
+	buf []byte
+}
+
+var _ flow.MsgReadWriter = (*framer)(nil)
+
+func (f *framer) WriteMsg(data ...[]byte) (int, error) {
+	// Compute the message size.
+	msgSize := 0
+	for _, b := range data {
+		msgSize += len(b)
+	}
+	// Construct a buffer to write that has space for the 3 bytes of framing.
+	// If a previous buffer is large enough, reuse it.
+	bufSize := msgSize + 3
+	if bufSize > len(f.buf) {
+		f.buf = make([]byte, bufSize)
+	}
+	if err := write3ByteUint(f.buf[:3], msgSize); err != nil {
+		return 0, err
+	}
+	head := 3
+	for _, b := range data {
+		l := len(b)
+		copy(f.buf[head:head+l], b)
+		head += l
+	}
+	// Write the buffer to the io.ReadWriter. Remove the frame size
+	// from the returned number of bytes written.
+	n, err := f.Write(f.buf[:bufSize])
+	if err != nil {
+		return n - 3, err
+	}
+	return n - 3, nil
+}
+
+func (f *framer) ReadMsg() ([]byte, error) {
+	// Read the message size.
+	frame := make([]byte, 3)
+	if _, err := io.ReadFull(f, frame); err != nil {
+		return nil, err
+	}
+	msgSize := read3ByteUint(frame)
+	// Read the message.
+	msg := make([]byte, msgSize)
+	if _, err := io.ReadFull(f, msg); err != nil {
+		return nil, err
+	}
+	return msg, nil
+}
+
+func write3ByteUint(dst []byte, n int) error {
+	if n >= (1<<24) || n < 0 {
+		return NewErrLargerThan3ByteUInt(nil)
+	}
+	dst[0] = byte((n & 0xff0000) >> 16)
+	dst[1] = byte((n & 0x00ff00) >> 8)
+	dst[2] = byte(n & 0x0000ff)
+	return nil
+}
+
+func read3ByteUint(src []byte) int {
+	return int(src[0])<<16 | int(src[1])<<8 | int(src[2])
+}
diff --git a/runtime/internal/flow/manager/framer_test.go b/runtime/internal/flow/manager/framer_test.go
new file mode 100644
index 0000000..7710f7d
--- /dev/null
+++ b/runtime/internal/flow/manager/framer_test.go
@@ -0,0 +1,49 @@
+// 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 manager
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestFramer(t *testing.T) {
+	b := &bytes.Buffer{}
+	f := &framer{ReadWriter: b}
+	bufs := [][]byte{[]byte("read "), []byte("this "), []byte("please.")}
+	want := []byte("read this please.")
+	l := len(want)
+	if n, err := f.WriteMsg(bufs...); err != nil || n != l {
+		t.Fatalf("got %v, %v, want %v, nil", n, err, l)
+	}
+	if got, err := f.ReadMsg(); err != nil || !bytes.Equal(got, want) {
+		t.Errorf("got %v, %v, want %v, nil", got, err, want)
+	}
+	// Framing a smaller message afterwards should reuse the internal buffer
+	// from the first sent message.
+	bufs = [][]byte{[]byte("read "), []byte("this "), []byte("too.")}
+	want = []byte("read this too.")
+	oldBufferLen := l + 3
+	l = len(want)
+	if n, err := f.WriteMsg(bufs...); err != nil || n != l {
+		t.Fatalf("got %v, %v, want %v, nil", n, err, l)
+	}
+	if got, err := f.ReadMsg(); err != nil || !bytes.Equal(got, want) {
+		t.Errorf("got %v, %v, want %v, nil", got, err, want)
+	}
+	if len(f.buf) != oldBufferLen {
+		t.Errorf("framer internal buffer should have been reused")
+	}
+	// Sending larger message afterwards should work as well.
+	bufs = [][]byte{[]byte("read "), []byte("this "), []byte("way bigger message.")}
+	want = []byte("read this way bigger message.")
+	l = len(want)
+	if n, err := f.WriteMsg(bufs...); err != nil || n != l {
+		t.Fatalf("got %v, %v, want %v, nil", n, err, l)
+	}
+	if got, err := f.ReadMsg(); err != nil || !bytes.Equal(got, want) {
+		t.Errorf("got %v, %v, want %v, nil", got, err, want)
+	}
+}