blob: 9ad96b0385cc12610cd48d807016b8f40920d777 [file] [log] [blame]
// Copyright 2018 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 fidl
import (
"syscall/zx"
"syscall/zx/zxwait"
)
// ServiceRequest is an abstraction over a FIDL interface request which is
// intended to be used as part of service discovery.
type ServiceRequest interface {
// Name returns the name of the service being requested.
Name() string
// ToChannel returns the underlying channel of the ServiceRequest.
ToChannel() zx.Channel
}
// InterfaceRequest is a wrapper type around a channel and represents the server side
// of a FIDL interface, to be sent to a server as a request.
type InterfaceRequest struct {
zx.Channel
}
// NewInterfaceRequest generates two sides of a channel with one layer of
// type casts out of the way to minimize the amount of generated code. Semantically,
// the two sides of the channel represent the interface request and the client
// side of the interface (the proxy). It returns an error on failure.
func NewInterfaceRequest() (InterfaceRequest, *ChannelProxy, error) {
h0, h1, err := zx.NewChannel(0)
if err != nil {
return InterfaceRequest{}, nil, err
}
return InterfaceRequest{Channel: h0}, &ChannelProxy{Channel: h1}, nil
}
// Proxy represents the client side of a FIDL interface.
type Proxy interface {
IsValid() bool
SendNew(ordinal uint32, req Message) error
RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error
CallNew(ordinal uint32, req Message, resp Message) error
// TODO(pascallouis): delete when migration is over
Send(ordinal uint32, req Payload) error
Recv(ordinal uint32, resp Payload, gen_ordinal ...uint32) error
Call(ordinal uint32, req Payload, resp Payload) error
}
// Stub represents a generated type which wraps the server-side implementation of a
// FIDL interface.
//
// It contains logic which is able to dispatch into the correct implementation given
// the incoming message ordinal and its data.
type Stub interface {
// Dispatch dispatches into the appropriate method implementation for a FIDL
// interface by using the ordinal.
//
// It also takes the data as bytes and transforms it into arguments usable by
// the method implementation. It then optionally returns a response if the
// method has a response.
DispatchNew(ordinal uint32, bytes []byte, handles []zx.Handle) (Message, error)
// TODO(pascallouis): delete post migration.
Dispatch(ordinal uint32, bytes []byte, handles []zx.Handle) (Payload, error)
}
// ChannelProxy a Proxy that is backed by a channel.
type ChannelProxy struct {
// Channel is the underlying channel endpoint for this interface.
zx.Channel
}
// Assert that ChannelProxy implements the Proxy interface.
var _ Proxy = &ChannelProxy{}
// IsValid returns true if the underlying channel is a valid handle.
func (p ChannelProxy) IsValid() bool {
h := zx.Handle(p.Channel)
return h.IsValid()
}
// Send sends the request over the channel with the specified ordinal
// without a response.
func (p *ChannelProxy) SendNew(ordinal uint32, req Message) error {
respb := messageBytesPool.Get().([]byte)
resph := messageHandlesPool.Get().([]zx.Handle)
defer messageBytesPool.Put(respb)
defer messageHandlesPool.Put(resph)
// Marshal the message into the buffer.
header := MessageHeader{
Txid: 0, // Txid == 0 for messages without a response.
Ordinal: ordinal,
}
nb, nh, err := marshalHeaderThenMessage(&header, req, respb[:], resph[:])
if err != nil {
return err
}
// Write the encoded bytes to the channel.
return p.Channel.Write(respb[:nb], resph[:nh], 0)
}
// Recv waits for an event and writes the response into the response.
func (p *ChannelProxy) RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error {
respb := messageBytesPool.Get().([]byte)
resph := messageHandlesPool.Get().([]zx.Handle)
defer messageBytesPool.Put(respb)
defer messageHandlesPool.Put(resph)
// Wait on the channel to be readable or close.
h := zx.Handle(p.Channel)
sigs, err := zxwait.Wait(h,
zx.SignalChannelReadable|zx.SignalChannelPeerClosed,
zx.TimensecInfinite,
)
if err != nil {
return err
}
// If it is closed and not readable, let's just report that and stop here.
if (sigs&zx.SignalChannelPeerClosed) != 0 && (sigs&zx.SignalChannelReadable) == 0 {
return zx.Error{Status: zx.ErrPeerClosed}
}
// Otherwise, now we can read!
nb, nh, err := p.Channel.Read(respb[:], resph[:], 0)
if err != nil {
return err
}
// Unmarshal the message.
var header MessageHeader
if err := unmarshalHeaderThenMessage(respb[:nb], resph[:nh], &header, resp); err != nil {
return err
}
// TODO(FIDL-425): Remove temporary handling of two ordinals.
var expectedOrdinal bool
if len(gen_ordinal) == 0 {
expectedOrdinal = header.Ordinal == ordinal
} else {
expectedOrdinal = header.Ordinal == ordinal || header.Ordinal == gen_ordinal[0]
}
if !expectedOrdinal {
return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
}
return nil
}
// Call sends the request over the channel with the specified ordinal
// and synchronously waits for a response. It then writes the response into the
// response.
func (p *ChannelProxy) CallNew(ordinal uint32, req Message, resp Message) error {
respb := messageBytesPool.Get().([]byte)
resph := messageHandlesPool.Get().([]zx.Handle)
defer messageBytesPool.Put(respb)
defer messageHandlesPool.Put(resph)
// Marshal the message into the buffer
header := MessageHeader{
Ordinal: ordinal,
}
nb, nh, err := marshalHeaderThenMessage(&header, req, respb[:], resph[:])
if err != nil {
return err
}
// Make the IPC call.
cnb, cnh, err := p.Channel.Call(0, zx.TimensecInfinite, respb[:nb], resph[:nh], respb[:], resph[:])
if err != nil {
return err
}
// Unmarshal the message.
if err := unmarshalHeaderThenMessage(respb[:cnb], resph[:cnh], &header, resp); err != nil {
return err
}
if header.Ordinal != ordinal {
return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
}
return nil
}
// SocketControlProxy is a Proxy that is backed by the control plane of a socket.
type SocketControlProxy struct {
// Socket is the underlying socket transport for this interface.
zx.Socket
}
// Assert that SocketControlProxy implements the Proxy interface.
var _ Proxy = &SocketControlProxy{}
// IsValid returns true if the underlying channel is a valid handle.
func (p SocketControlProxy) IsValid() bool {
h := zx.Handle(p.Socket)
return h.IsValid()
}
// Send sends the request over the socket control plane with the
// specified ordinal without a response.
func (p *SocketControlProxy) SendNew(ordinal uint32, req Message) error {
respb := messageBytesPool.Get().([]byte)
defer messageBytesPool.Put(respb)
// Marshal the message into the buffer.
header := MessageHeader{
Txid: 0, // Txid == 0 for messages without a response.
Ordinal: ordinal,
}
nb, _, err := marshalHeaderThenMessage(&header, req, respb[:], nil)
if err != nil {
return err
}
// Write the encoded bytes to the socket control plane.
_, err = p.Socket.Write(respb[:nb], zx.SocketControl)
return err
}
// Recv waits for an event and writes the response.
func (p *SocketControlProxy) RecvNew(ordinal uint32, resp Message, gen_ordinal ...uint32) error {
respb := messageBytesPool.Get().([]byte)
defer messageBytesPool.Put(respb)
// Wait on the socket control plane to be readable or close.
h := zx.Handle(p.Socket)
sigs, err := zxwait.Wait(h,
zx.SignalSocketControlReadable|zx.SignalSocketPeerClosed,
zx.TimensecInfinite,
)
if err != nil {
return err
}
// If it is closed and not readable, let's just report that and stop here.
if (sigs&zx.SignalSocketPeerClosed) != 0 && (sigs&zx.SignalSocketControlReadable) == 0 {
return zx.Error{Status: zx.ErrPeerClosed}
}
// Otherwise, now we can read!
nb, err := p.Socket.Read(respb[:], zx.SocketControl)
if err != nil {
return err
}
// Unmarshal the message.
var header MessageHeader
if err := unmarshalHeaderThenMessage(respb[:nb], nil, &header, resp); err != nil {
return err
}
// TODO(FIDL-425): Remove temporary handling of two ordinals.
var expectedOrdinal bool
if len(gen_ordinal) == 0 {
expectedOrdinal = header.Ordinal == ordinal
} else {
expectedOrdinal = header.Ordinal == ordinal || header.Ordinal == gen_ordinal[0]
}
if !expectedOrdinal {
return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
}
return nil
}
// Call sends the request over the socket control plane with the specified
// ordinal and waits for a response. It then writes the response into the response.
func (p *SocketControlProxy) CallNew(ordinal uint32, req Message, resp Message) error {
if err := p.SendNew(ordinal, req); err != nil {
return err
}
if err := p.RecvNew(ordinal, resp); err != nil {
return err
}
return nil
}