| // 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 |
| 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. |
| 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 payload over the channel with the specified ordinal |
| // without a response. |
| func (p *ChannelProxy) Send(ordinal uint32, req Payload) 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 := MarshalMessage(&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 payload. |
| func (p *ChannelProxy) Recv(ordinal uint32, resp Payload, 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 := UnmarshalMessage(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 payload over the channel with the specified ordinal |
| // and synchronously waits for a response. It then writes the response into the |
| // response payload. |
| func (p *ChannelProxy) Call(ordinal uint32, req Payload, resp Payload) 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 := MarshalMessage(&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 := UnmarshalMessage(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 payload over the socket control plane with the |
| // specified ordinal without a response. |
| func (p *SocketControlProxy) Send(ordinal uint32, req Payload) 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 := MarshalMessage(&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 into the response payload. |
| func (p *SocketControlProxy) Recv(ordinal uint32, resp Payload, 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 := UnmarshalMessage(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 payload over the socket control plane with the specified |
| // ordinal and waits for a response. It then writes the response into the response |
| // payload. |
| func (p *SocketControlProxy) Call(ordinal uint32, req Payload, resp Payload) error { |
| if err := p.Send(ordinal, req); err != nil { |
| return err |
| } |
| if err := p.Recv(ordinal, resp); err != nil { |
| return err |
| } |
| return nil |
| } |