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)
+ }
+}