blob: b3a89a90b003a86141044d2ab1b4976610e447c4 [file] [log] [blame]
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build fuchsia
package zxsocket
import (
"unsafe"
"syscall/zx"
)
const (
// MessageChunkSize is the largest size of 'data' in an zxsocket message
MessageChunkSize = 900
// MessageSizeMax is the largest size of a zxsocket message
MessageSizeMax = uint32(unsafe.Sizeof(Msg{}))
// MessageHeaderSize is the size of zxsocket message without 'data'
MessageHeaderSize = uint32(unsafe.Sizeof(MsgHeader{}))
// MessageMaxHandles is the maximum number of handles a message may carry.
// In reality, zx.Sockets can't hold handles, but this is used to support
// the deprecated RemoteIO protocol over a socket.
MessageMaxHandles = 3
)
// Custom errors for zxsocket RemoteIO.
var (
// If returned from dispatcher callback, indicates that the dispatcher should immediately
// disconnect with no additional callbacks.
ErrDisconnectNoCallback = zx.Error{Status: 1, Text: "fdio.Dispatcher"}
// If returned from dispatcher callback, indicates that there are no more messages to read.
ErrNoWork = zx.Error{Status: -9999, Text: "fdio.Dispatcher.NoWork"}
// If returned from dispatcher callback, indicates that the message was handed to another
// server.
ErrIndirect = zx.Error{Status: -9998, Text: "fdio.Dispatcher.Indirect"}
)
const (
OpFlagOneHandle = uint32(0x100 + iota)
)
// Values for op. Each one will signify a request for a different operation.
// This is a copy of the list in fdio/message.go, with the non-socket-related
// options removed. Note that these are deprecated. We will be migrating to
// FIDL2 ordinals soon.
const (
_ = uint32(iota)
OpClose
OpClone = uint32(iota) | OpFlagOneHandle
OpOpen = uint32(iota) | OpFlagOneHandle
_ = uint32(iota) // OpMisc
OpRead
OpWrite
_ // OpSeek
_ // OpStat
_ // OpReaddir
OpIoctl
_ // OpUnlink
_ // OpReadAt
_ // OpWriteAt
_ // OpTruncate
_ = uint32(iota) | OpFlagOneHandle // OpRename
OpConnect = uint32(iota)
OpBind
OpListen
OpGetSockname
OpGetPeerName
OpGetSockOpt
OpSetSockOpt
OpGetAddrInfo
_ // OpSetAttr
_ // OpSync
_ = uint32(iota) | OpFlagOneHandle // OpLink
_ = uint32(iota) // OpMmap
OpFcntl
OpNumOps = uint32(iota) // The total number of operations
)
type Protocol uint32
// All available FDIO protocols
const (
// The SERVICE protocol allows access to a generic interface.
ProtocolService = Protocol(iota)
// The FILE protocol allows access to a regular file.
ProtocolFile
// The DIRECTORY protocol allows access to a directory, which may
// contain additional nodes.
ProtocolDirectory
// The PIPE protocol uses message ports as simple, no-flow-control io pipes.
ProtocolPipe
// The VMOFILE protocol accesses a file as a VMO.
ProtocolVMOFile
// The DEVICE protocol allows access to a generic device.
ProtocolDevice
// The SOCKET protocol provides socket access.
ProtocolSocket
ProtocolSocketConnected
)
const (
OpenFlagDescribe = 0x00800000
)
// FIDL2 message header
type FIDLHeader struct {
Txid uint32
reserved0 uint32
flags uint32
op uint32
}
type MsgHeader struct {
FIDLHeader
Datalen uint32
Arg int32
arg2 int64
reserved1 int32
Hcount uint32
Handle [4]zx.Handle // 3 handles + reply pipe, unused here though.
}
func (m *MsgHeader) Op() uint32 {
return m.op & 0x3FFF
}
func (m *MsgHeader) SetOp(v uint32) {
m.op = (v & 0x3FFF)
}
func (m *MsgHeader) OpHandleCount() uint32 {
return (m.op >> 8) & 3
}
func (m *MsgHeader) Off() int64 {
return m.arg2
}
func (m *MsgHeader) SetOff(v int64) {
m.arg2 = v
}
func (m *MsgHeader) Mode() uint32 {
return uint32(m.arg2)
}
func (m *MsgHeader) SetMode(v uint32) {
m.arg2 = int64(v)
}
func (m *MsgHeader) Protocol() Protocol {
return Protocol(m.arg2)
}
func (m *MsgHeader) SetProtocol(p Protocol) {
m.arg2 = int64(p)
}
func (m *MsgHeader) IoctlOp() uint32 {
return uint32(m.arg2)
}
func (m *MsgHeader) SetIoctlOp(v uint32) {
m.arg2 = int64(v)
}
func (m *MsgHeader) FcntlFlags() uint32 {
return uint32(m.arg2)
}
func (m *MsgHeader) SetFcntlFlags(v uint32) {
m.arg2 = int64(v)
}
// Msg is the message sent in the zxsocket protocol.
type Msg struct {
MsgHeader
Data [MessageChunkSize]uint8
}
func (m *Msg) CallMsg(c *zx.Channel) (numBytes, numHandles uint32, err error) {
wData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:MessageHeaderSize+m.Datalen]
var wHandles []zx.Handle
if m.Hcount > 0 {
wHandles = m.Handle[:m.Hcount]
}
rData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:]
rHandles := m.Handle[:]
numBytes, numHandles, err = c.Call(0, zx.TimensecInfinite, wData, wHandles, rData, rHandles)
m.Hcount = numHandles
return
}
// ReadMsg reads a message from a socket.
func (m *Msg) ReadMsg(s zx.Socket) (numBytes int, numHandles uint32, err error) {
msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
// TODO: why is numBytes int?
numBytes, err = s.Read(msgBytes[:], zx.SocketControl)
numHandles = 0
m.Hcount = numHandles
return
}
// WriteMsg writes a message to a socket.
func (m *Msg) WriteMsg(s zx.Socket) (int, error) {
msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
data := msgBytes[:MessageHeaderSize+m.Datalen]
return s.Write(data, zx.SocketControl)
}
// WriteMsg writes a message to a channel.
func (m *Msg) WriteChannelMsg(c *zx.Channel) error {
msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
data := msgBytes[:MessageHeaderSize+m.Datalen]
var handles []zx.Handle
if m.Hcount > 0 {
handles = m.Handle[:m.Hcount]
}
return c.Write(data, handles, 0)
}
func (m *Msg) IsValid() bool {
if m.Datalen > MessageChunkSize || m.Hcount != 0 {
return false
}
return true
}
func (m *Msg) IsValidIncoming(size uint32) bool {
if (size < MessageHeaderSize) || m.Datalen != (size-MessageHeaderSize) {
return false
}
return m.IsValid()
}