blob: 8455cd4b1e1323c4a11fc7a9120de09dfde2337d [file] [log] [blame]
// Copyright 2015 The Chromium 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 bindings
import (
"fmt"
"mojo/public/go/system"
)
const (
// Flag for a header of a simple message.
MessageNoFlag = 0
// Flag for a header of a message that expected a response.
MessageExpectsResponseFlag = 1 << 0
// Flag for a header of a message that is a response.
MessageIsResponseFlag = 1 << 1
dataHeaderSize = 8
defaultAlignment = 8
pointerBitSize = 64
)
var mapHeader DataHeader
func init() {
mapHeader = DataHeader{24, 2}
}
// Payload is an interface implemented by a mojo struct that can encode/decode
// itself into mojo archive format.
type Payload interface {
Encode(encoder *Encoder) error
Decode(decoder *Decoder) error
}
// DataHeader is a header for a mojo complex element.
type DataHeader struct {
Size uint32
ElementsOrVersion uint32
}
// MessageHeader is a header information for a message.
type MessageHeader struct {
Type uint32
Flags uint32
RequestId uint64
}
func (h *MessageHeader) Encode(encoder *Encoder) error {
encoder.StartStruct(h.dataSize(), h.numFields())
if err := encoder.WriteUint32(h.Type); err != nil {
return err
}
if err := encoder.WriteUint32(h.Flags); err != nil {
return err
}
if h.RequestId != 0 {
if err := encoder.WriteUint64(h.RequestId); err != nil {
return err
}
}
return encoder.Finish()
}
func (h *MessageHeader) Decode(decoder *Decoder) error {
header, err := decoder.StartStruct()
if err != nil {
return err
}
numFields := header.ElementsOrVersion
if numFields < 2 || numFields > 3 {
return fmt.Errorf("Invalid message header: it should have 2 or 3 fileds, but has %d", numFields)
}
if h.Type, err = decoder.ReadUint32(); err != nil {
return err
}
if h.Flags, err = decoder.ReadUint32(); err != nil {
return err
}
if numFields == 3 {
if h.Flags != MessageExpectsResponseFlag && h.Flags != MessageIsResponseFlag {
return fmt.Errorf("Message header flags(%v) should be MessageExpectsResponseFlag or MessageIsResponseFlag", h.Flags)
}
if h.RequestId, err = decoder.ReadUint64(); err != nil {
return err
}
} else {
if h.Flags != MessageNoFlag {
return fmt.Errorf("Message header flags(%v) should be MessageNoFlag", h.Flags)
}
}
return decoder.Finish()
}
func (h *MessageHeader) dataSize() uint32 {
var size uint32
size = 2 * 4
if h.RequestId != 0 {
size += 8
}
return size
}
func (h *MessageHeader) numFields() uint32 {
if h.RequestId != 0 {
return 3
} else {
return 2
}
}
// Message is a a raw message to be sent/received from a message pipe handle
// which contains a message header.
type Message struct {
Header MessageHeader
Bytes []byte
Handles []system.UntypedHandle
Payload []byte
}
func newMessage(header MessageHeader, bytes []byte, handles []system.UntypedHandle) *Message {
return &Message{header, bytes, handles, bytes[header.dataSize()+dataHeaderSize:]}
}
// DecodePayload decodes the provided payload from the message.
func (m *Message) DecodePayload(payload Payload) error {
decoder := NewDecoder(m.Payload, m.Handles)
if err := payload.Decode(decoder); err != nil {
return err
}
return nil
}
// EncodeMessage returns a message with provided header that has provided
// payload encoded in mojo archive format.
func EncodeMessage(header MessageHeader, payload Payload) (*Message, error) {
encoder := NewEncoder()
if err := header.Encode(encoder); err != nil {
return nil, err
}
if err := payload.Encode(encoder); err != nil {
return nil, err
}
if bytes, handles, err := encoder.Data(); err != nil {
return nil, err
} else {
return newMessage(header, bytes, handles), nil
}
}
// ParseMessage parses message header from byte buffer with attached handles
// and returnes parsed message.
func ParseMessage(bytes []byte, handles []system.UntypedHandle) (*Message, error) {
decoder := NewDecoder(bytes, []system.UntypedHandle{})
var header MessageHeader
if err := header.Decode(decoder); err != nil {
return nil, err
}
return newMessage(header, bytes, handles), nil
}