[zx][fdio][net] Convert net FDIO to use FIDL
This change also cleans up a bunch of things.
US-462
Change-Id: If9cc75912bcba92905e8f7162886a34b39d09347
diff --git a/src/net/fd_fuchsia.go b/src/net/fd_fuchsia.go
index f2c9a87..606daa0 100644
--- a/src/net/fd_fuchsia.go
+++ b/src/net/fd_fuchsia.go
@@ -9,29 +9,16 @@
"os"
"runtime"
"syscall"
- "syscall/zx"
- "syscall/zx/fdio"
"syscall/zx/mxnet"
"syscall/zx/zxsocket"
"time"
)
-func mxStatus(err error) zx.Status {
- if err == nil {
- return zx.ErrOk
- }
- if status, ok := err.(zx.Error); ok {
- return status.Status
- }
- return zx.ErrInternal
-}
-
// Network file descriptor.
type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods
fdmu fdMutex
- hsrc *os.File
- m fdio.FDIO
+ sock *zxsocket.Socket
// immutable until Close
net string
@@ -55,7 +42,7 @@
}
func (fd *netFD) Read(b []byte) (n int, err error) {
- return fd.m.Read(b)
+ return fd.sock.Read(b)
}
func (fd *netFD) Write(b []byte) (n int, err error) {
@@ -64,7 +51,7 @@
// that behavior here:
l, t := len(b), 0
for {
- n, err := fd.m.Write(b)
+ n, err := fd.sock.Write(b)
t += n
if t == l {
return t, err
@@ -80,13 +67,13 @@
}
func (fd *netFD) recvMsg(b []byte) (n, flags int, addr string, port uint16, err error) {
- data, flags, addr, port, err := fd.m.(*zxsocket.Socket).RecvMsg(len(b))
+ data, flags, addr, port, err := fd.sock.RecvMsg(len(b))
n = copy(b, data)
return n, flags, addr, port, err
}
func (fd *netFD) sendMsg(b []byte, addr string, port uint16) (n int, err error) {
- return fd.m.(*zxsocket.Socket).SendMsg(b, addr, port)
+ return fd.sock.SendMsg(b, addr, port)
}
func (fd *netFD) closeRead() error {
@@ -98,10 +85,12 @@
}
func (fd *netFD) Close() error {
- return fd.hsrc.Close()
+ return fd.sock.Close()
}
func (fd *netFD) dup() (*os.File, error) {
+ // TODO(mknyszek): fd.sock is an FDIO so one can make an FD from it to
+ // implement this.
return nil, errors.New("net: dup not implemented on fuchsia")
}
@@ -123,13 +112,12 @@
}
defer fd.readUnlock()
- m, err := zxsocket.Accept(fd.m)
+ sock, err := fd.sock.Accept()
if err != nil {
return nil, err
}
netfd = &netFD{
- hsrc: os.NewFile(uintptr(syscall.OpenFDIO(m)), "socket"),
- m: m,
+ sock: sock,
family: fd.family,
sotype: fd.sotype,
net: fd.net,
@@ -156,7 +144,7 @@
}
func (fd *netFD) setAddr() {
- fd.laddr = fd.asAddr(zxsocket.GetSockName(fd.m))
- fd.raddr = fd.asAddr(zxsocket.GetPeerName(fd.m))
+ fd.laddr = fd.asAddr(fd.sock.SockName())
+ fd.raddr = fd.asAddr(fd.sock.PeerName())
runtime.SetFinalizer(fd, (*netFD).Close)
}
diff --git a/src/net/ipsock_fuchsia.go b/src/net/ipsock_fuchsia.go
index 59d6110..a3fc167 100644
--- a/src/net/ipsock_fuchsia.go
+++ b/src/net/ipsock_fuchsia.go
@@ -7,7 +7,6 @@
import (
"context"
"errors"
- "os"
"sync"
"syscall"
"syscall/zx"
@@ -93,16 +92,16 @@
}
proto := syscall.IPPROTO_IP
- var m fdio.FDIO
+ var sock *zxsocket.Socket
// Wait for the network stack to publish the socket device.
// See similar logic in zircon/system/ulib/fdio/bsdsocket.c.
for i := 0; i < 40; i++ {
c := zx.Channel(getSocketProvider())
if c.Handle().IsValid() {
sp := zxnet.LegacySocketProviderInterface(fidl.Proxy{Channel: c})
- sock, _, err := sp.OpenSocket(zxnet.SocketDomain(family), zxnet.SocketType(sotype), zxnet.SocketProtocol(proto))
+ s, _, err := sp.OpenSocket(zxnet.SocketDomain(family), zxnet.SocketType(sotype), zxnet.SocketProtocol(proto))
if err == nil {
- m, _ = zxsocket.NewSocket(*sock.Handle())
+ sock = zxsocket.NewSocket(s)
break
}
}
@@ -112,12 +111,11 @@
return nil, err
}
if sotype == syscall.SOCK_DGRAM {
- zxsocket.SetDgram(m)
+ sock.SetDgram()
}
fd = &netFD{
- hsrc: os.NewFile(uintptr(syscall.OpenFDIO(m)), "socket"),
- m: m,
+ sock: sock,
family: family,
sotype: sotype,
net: net,
@@ -128,14 +126,14 @@
return nil, err
}
if addr != "" || port != 0 {
- if err := zxsocket.Bind(fd.m, addr, port); err != nil {
+ if err := fd.sock.Bind(addr, port); err != nil {
return nil, err
}
}
if raddr == nil {
switch sotype {
case syscall.SOCK_STREAM:
- if err := zxsocket.ListenStream(m, listenerBacklog); err != nil {
+ if err := fd.sock.ListenStream(listenerBacklog); err != nil {
return nil, err
}
case syscall.SOCK_DGRAM:
@@ -148,7 +146,7 @@
if err != nil {
return nil, err
}
- if err := zxsocket.Connect(fd.m, addr, port); err != nil {
+ if err := fd.sock.Connect(addr, port); err != nil {
return nil, err
}
fd.isConnected = true
diff --git a/src/syscall/zx/zxsocket/client.go b/src/syscall/zx/zxsocket/client.go
index 0a97fa6..ce575ee 100644
--- a/src/syscall/zx/zxsocket/client.go
+++ b/src/syscall/zx/zxsocket/client.go
@@ -7,11 +7,54 @@
package zxsocket
import (
+ "errors"
"syscall/zx"
- "syscall/zx/fdio"
+ "syscall/zx/mxerror"
+ "syscall/zx/mxnet"
"unsafe"
)
+
+// Bind is BSD Sockets bind on a *Socket.
+func (s *Socket) Bind(addr mxnet.Addr, port uint16) error {
+ b := make([]byte, mxnet.SockaddrLen)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+ if err != nil {
+ return err
+ }
+ b = b[:addrlen]
+ _, err = s.Misc(OpBind, 0, b, nil, nil)
+ return err
+}
+
+// Connect is BSD Sockets connect on a *Socket.
+func (s *Socket) Connect(addr mxnet.Addr, port uint16) error {
+ b := make([]byte, mxnet.SockaddrLen)
+ addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+ if err != nil {
+ return err
+ }
+ b = b[:addrlen]
+
+ _, err = s.Misc(OpConnect, 0, b, nil, nil)
+ if err != nil && mxerror.Status(err) == zx.ErrShouldWait {
+ obs, err := s.Wait(mxnet.MXSIO_SIGNAL_OUTGOING, zx.TimensecInfinite)
+ switch mxerror.Status(err) {
+ case zx.ErrOk:
+ switch {
+ case obs&mxnet.MXSIO_SIGNAL_CONNECTED != 0:
+ return nil
+ default:
+ // TODO: Use opSetSockOpt to get the reason of the error.
+ return errors.New("zxsocket.Connect: OpConnect was not successful")
+ }
+ default:
+ return err
+ }
+ }
+ return err
+}
+
// txn completes the client-side part of the RIO transaction.
func (s *Socket) txn(msg *Msg) (uint32, error) {
if !msg.IsValid() {
@@ -40,78 +83,68 @@
return uint32(status), nil
}
-func (s *Socket) Close() error {
- var msg Msg
- msg.SetOp(OpClose)
+func (s *Socket) ListenStream(backlog int) error {
+ b := make([]byte, 4)
+ b[0] = byte(backlog)
+ b[1] = byte(backlog >> 8)
+ b[2] = byte(backlog >> 16)
+ b[3] = byte(backlog >> 24)
+ _, err := s.Misc(OpListen, 0, b, nil, nil)
+ return err
+}
- _, err := s.txn(&msg)
+func (s *Socket) Accept() (*Socket, error) {
+ if s.flags&SocketFlagsDidListen == 0 {
+ return nil, errors.New("zxsocket.Accept: listen was not called")
+ }
- s.socket.Close()
- s.socket = 0
+ var h zx.Handle
+ for {
+ err := s.socket.Accept(&h)
+ if err == nil {
+ break
+ }
+ if mxerror.Status(err) != zx.ErrShouldWait {
+ return nil, err
+ }
+ s.socket.Handle().SignalPeer(0, zx.SignalUser7)
+ // TODO: non-blocking support, pass this to the poller
+ const ZX_SOCKET_ACCEPT = zx.SignalSocketAccept
+ const ZX_SOCKET_PEER_CLOSED = zx.SignalSocketPeerClosed
+ pending, err := s.Wait(ZX_SOCKET_ACCEPT|ZX_SOCKET_PEER_CLOSED, zx.TimensecInfinite)
+ if err != nil {
+ return nil, err
+ }
+ if pending&ZX_SOCKET_ACCEPT != 0 {
+ continue
+ }
+ if pending&ZX_SOCKET_PEER_CLOSED != 0 {
+ return nil, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket"}
+ }
+ }
+ return NewSocket(zx.Socket(h)), nil
+}
+func (s *Socket) getName(op uint32, debug string) (addr mxnet.Addr, port uint16, err error) {
+ out := make([]byte, mxnet.SockaddrReplyLen)
+ _, err = s.Misc(OpGetSockname, 0, nil, out, nil)
if err != nil {
- return err
+ return "", 0, err
}
- return nil
-}
-
-func closeAll(handles []zx.Handle) {
- for i := range handles {
- handles[i].Close()
- }
-}
-
-// Consumes handles, wrapping them in fdio object or closing them on error.
-func createFromHandles(handle zx.Handle, info fdio.ObjectInfo) (fdio.FDIO, error) {
- handles := append([]zx.Handle{handle}, info.GetHandles()...)
- switch info.Tag {
- case fdio.ProtocolSocket:
- handles[0].Close()
- return NewSocket(handles[1])
- default:
- println("Unknown fdio protocol, ", info.Tag)
- // In the error case, the server may have given us handles -- close them
- closeAll(handles)
- return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket"}
- }
-}
-
-func OpenHandle(rio zx.Channel, path string, flags uint32, mode uint32) (fdio.FDIO, error) {
- c, ro, err := fdio.GetObject(rio, OpOpen, path, flags, mode)
+ addr, port, err = mxnet.DecodeSockaddr(out)
if err != nil {
- return nil, err
+ return "", 0, err
}
- return createFromHandles(zx.Handle(c), ro.Info)
+
+ return addr, port, nil
}
-// TODO(smklein): Remove; this function is a subset of "Ioctl".
-func (s *Socket) IoctlSetHandle(op uint32, in zx.Handle) error {
- return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.IoctlSetHandle"}
+func (s *Socket) SockName() (addr mxnet.Addr, port uint16, err error) {
+ return s.getName(OpGetSockname, "GetSockName")
}
-func (s *Socket) Ioctl(op uint32, in, out []byte) ([]zx.Handle, error) {
- var msg Msg
- if len(in) > fdio.IoctlMaxInput {
- return nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Ioctl"}
- }
-
- if fdio.IoctlKind(op) != fdio.IoctlKindDefault {
- return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Ioctl"}
- }
-
- msg.SetOp(OpIoctl)
- msg.Datalen = uint32(len(in))
- msg.Arg = int32(len(out))
- msg.SetIoctlOp(op)
- copy(msg.Data[:], in)
-
- _, err := s.txn(&msg)
- if err != nil {
- return nil, err
- }
-
- copy(out, msg.Data[:msg.Datalen])
- return nil, nil
+func (s *Socket) PeerName() (addr mxnet.Addr, port uint16, err error) {
+ return s.getName(OpGetPeerName, "GetPeerName")
}
func (s *Socket) Misc(op uint32, off int64, in, out []byte, handles []zx.Handle) (n int, err error) {
diff --git a/src/syscall/zx/zxsocket/message.go b/src/syscall/zx/zxsocket/message.go
index 9bf0c89..b3a89a9 100644
--- a/src/syscall/zx/zxsocket/message.go
+++ b/src/syscall/zx/zxsocket/message.go
@@ -10,7 +10,6 @@
"unsafe"
"syscall/zx"
- "syscall/zx/fdio"
)
const (
@@ -21,7 +20,24 @@
MessageSizeMax = uint32(unsafe.Sizeof(Msg{}))
// MessageHeaderSize is the size of zxsocket message without 'data'
- MessageHeaderSize = fdio.MessageHeaderSize
+ 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 (
@@ -65,14 +81,93 @@
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.
-// Its format must mirror fdio.Msg, though its Data field is a different size.
type Msg struct {
- fdio.MsgHeader
+ MsgHeader
Data [MessageChunkSize]uint8
}
diff --git a/src/syscall/zx/zxsocket/server.go b/src/syscall/zx/zxsocket/server.go
index 0299e8f..211babf 100644
--- a/src/syscall/zx/zxsocket/server.go
+++ b/src/syscall/zx/zxsocket/server.go
@@ -8,7 +8,6 @@
import (
"syscall/zx"
- "syscall/zx/fdio"
)
// ServerHandler is the type of the callback which contains the remoteio "server". It is called from
@@ -25,19 +24,19 @@
serverCb := cb.(ServerHandler)
if h == 0 {
// The remote side has been closed. Send our final callback and leave.
- msg.SetOp(fdio.OpClose)
+ msg.SetOp(OpClose)
msg.Arg = 0
msg.Datalen = 0
msg.Hcount = 0
serverCb(&msg, 0, cookie)
return nil
}
- msg.Hcount = fdio.MessageMaxHandles
+ msg.Hcount = MessageMaxHandles
numBytesInt, _, err := msg.ReadMsg(h)
numBytes := uint32(numBytesInt)
if err != nil {
if mxerr, hasStatus := err.(zx.Error); hasStatus && mxerr.Status == zx.ErrBadState {
- return fdio.ErrNoWork
+ return ErrNoWork
}
return err
}
@@ -45,10 +44,10 @@
return zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Handler"}
}
- isClose := (msg.Op() == fdio.OpClose)
+ isClose := (msg.Op() == OpClose)
status := serverCb(&msg, h, cookie)
msg.Arg = int32(status)
- if zx.Status(msg.Arg) == fdio.ErrIndirect.Status {
+ if zx.Status(msg.Arg) == ErrIndirect.Status {
// The callback is handling the reply itself
return nil
} else if status < 0 || !msg.IsValid() {
@@ -64,7 +63,7 @@
_, err = msg.WriteMsg(h)
if isClose {
// Signals that a close callback is not necessary -- the op has already completed
- return fdio.ErrDisconnectNoCallback
+ return ErrDisconnectNoCallback
}
return err
}
diff --git a/src/syscall/zx/zxsocket/socket.go b/src/syscall/zx/zxsocket/socket.go
index 01eb97b..4546800 100644
--- a/src/syscall/zx/zxsocket/socket.go
+++ b/src/syscall/zx/zxsocket/socket.go
@@ -7,15 +7,16 @@
package zxsocket
import (
- "errors"
"io"
"syscall/zx"
+ fidlIo "syscall/zx/io"
"syscall/zx/fdio"
+ "syscall/zx/mxerror"
"syscall/zx/mxnet"
"syscall/zx/zxwait"
)
-// Socket is an FDIO socket.
+// Socket is an fdio.FDIO socket.
type Socket struct {
socket zx.Socket
@@ -28,48 +29,86 @@
SocketFlagsDidListen = 1 << iota // zxsocket._DID_LISTEN
)
-// NewSocket creates a new zxsocket Socket.
-func NewSocket(handle zx.Handle) (*Socket, error) {
- s := &Socket{
- socket: zx.Socket(handle),
- }
- return s, nil
+func NewSocket(s zx.Socket) *Socket {
+ return &Socket{socket: s}
}
func (s *Socket) Wait(signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
return zxwait.Wait(zx.Handle(s.socket), signals, timeout)
}
-func ReadControl(s zx.Socket, data []byte) (n int, err error) {
- // c.f. zxsocket._read_control in zircon/system/ulib/fdio/remoteio.c
- for {
- n, err = s.Read(data, zx.SocketControl)
- switch zxStatus(err) {
- case zx.ErrOk:
- return n, nil
- case zx.ErrPeerClosed:
- return 0, io.EOF
- case zx.ErrShouldWait:
- obs, err := zxwait.Wait(zx.Handle(s), zx.SignalSocketControlReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
- switch zxStatus(err) {
- case zx.ErrOk:
- switch {
- case obs&zx.SignalSocketControlReadable != 0:
- continue
- case obs&zx.SignalSocketPeerClosed != 0:
- return 0, io.EOF
- }
- case zx.ErrBadHandle, zx.ErrCanceled:
- return 0, io.EOF
- default:
- return 0, err
- }
- default:
- return 0, err
- }
- }
+// Handles returns the underlying handles for this Socket.
+func (s *Socket) Handles() []zx.Handle {
+ return []zx.Handle{zx.Handle(s.socket)}
}
+// Clone makes a clone of the object.
+func (s *Socket) Clone() (fdio.FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Clone"}
+}
+
+// Close closes the object.
+func (s *Socket) Close() error {
+ if s.socket == 0 {
+ return nil
+ }
+ var msg Msg
+ msg.SetOp(OpClose)
+
+ _, err := s.txn(&msg)
+
+ s.socket.Close()
+ s.socket = 0
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// Sync implements fdio.FDIO for Socket.
+func (s *Socket) Sync() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// GetAttr implements fdio.FDIO for Socket.
+func (s *Socket) GetAttr() (fidlIo.NodeAttributes, error) {
+ return fidlIo.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// SetAttr implements fdio.FDIO for Socket.
+func (s *Socket) SetAttr(flags uint32, attr fidlIo.NodeAttributes) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Ioctl implements fdio.FDIO for Socket.
+func (s *Socket) Ioctl(op uint32, max uint64, in []byte, _ []zx.Handle) ([]byte, []zx.Handle, error) {
+ var msg Msg
+ if len(in) > fdio.IoctlMaxInput {
+ return nil, nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Ioctl"}
+ }
+
+ if fdio.IoctlKind(op) != fdio.IoctlKindDefault {
+ return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Ioctl"}
+ }
+
+ out := make([]byte, MessageSizeMax)
+ msg.SetOp(OpIoctl)
+ msg.Datalen = uint32(len(in))
+ msg.Arg = int32(len(out))
+ msg.SetIoctlOp(op)
+ copy(msg.Data[:], in)
+
+ _, err := s.txn(&msg)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ copy(out, msg.Data[:msg.Datalen])
+ return out[:msg.Datalen], nil, nil
+}
+
+// Read implements fdio.FDIO for Socket.
func (s *Socket) Read(data []byte) (n int, err error) {
if s.dgram {
b, _, _, _, err := s.RecvMsg(len(data))
@@ -79,14 +118,14 @@
// c.f. mxsio_read_stream in zircon/system/ulib/fdio/remoteio.c
for {
n, err = s.socket.Read(data, 0)
- switch zxStatus(err) {
+ switch mxerror.Status(err) {
case zx.ErrOk:
return n, nil
case zx.ErrPeerClosed:
return 0, io.EOF
case zx.ErrShouldWait:
obs, err := s.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
- switch zxStatus(err) {
+ switch mxerror.Status(err) {
case zx.ErrOk:
switch {
case obs&zx.SignalSocketReadable != 0:
@@ -105,27 +144,12 @@
}
}
+// ReadAt implements fdio.FDIO for Socket.
func (s *Socket) ReadAt(data []byte, off int64) (int, error) {
- return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.ReadAt"}
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
}
-func WriteControl(s zx.Socket, data []byte) (int, error) {
- // c.f. zxsocket._write_control
- for {
- n, err := s.Write(data, zx.SocketControl)
- switch zxStatus(err) {
- case zx.ErrOk:
- return n, nil
- case zx.ErrShouldWait:
- _, err := zxwait.Wait(zx.Handle(s), zx.SignalSocketControlWriteable, zx.TimensecInfinite)
- if err != nil {
- return n, err
- }
- continue
- }
- }
-}
-
+// Write implements fdio.FDIO for Socket.
func (s *Socket) Write(data []byte) (int, error) {
if s.dgram {
n, err := s.SendMsg(data, "", 0)
@@ -138,7 +162,7 @@
n, err := s.socket.Write(data, 0)
total += n
- switch zxStatus(err) {
+ switch mxerror.Status(err) {
case zx.ErrOk:
return total, nil
case zx.ErrShouldWait:
@@ -161,8 +185,49 @@
}
}
+// WriteAt implements fdio.FDIO for Socket.
func (s *Socket) WriteAt(data []byte, off int64) (int, error) {
- return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.WriteAt"}
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Seek implements fdio.FDIO for Socket.
+func (s *Socket) Seek(offset int64, whence int) (int64, error) {
+ return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Truncate implements fdio.FDIO for Socket.
+func (s *Socket) Truncate(length uint64) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Open implements fdio.FDIO for Socket.
+func (s *Socket) Open(path string, flags uint32, mode uint32) (fdio.FDIO, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Link implements fdio.FDIO for Socket.
+func (s *Socket) Link(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rename implements fdio.FDIO for Socket.
+func (s *Socket) Rename(oldpath, newpath string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Unlink implements fdio.FDIO for Socket.
+func (s *Socket) Unlink(path string) error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// ReadDirents implements fdio.FDIO for Socket.
+func (s *Socket) ReadDirents(max uint64) ([]byte, error) {
+ return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rewind implements fdio.FDIO for Socket.
+func (s *Socket) Rewind() error {
+ return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
}
func (s *Socket) RecvMsg(maxLen int) (b []byte, flags int, addr string, port uint16, err error) {
@@ -183,7 +248,7 @@
func (s *Socket) recvMsg(data []byte) (int, error) {
for {
n, err := s.socket.Read(data, 0)
- switch zxStatus(err) {
+ switch mxerror.Status(err) {
case zx.ErrOk:
return n, err
case zx.ErrShouldWait:
@@ -218,7 +283,7 @@
for {
n, err := s.socket.Write(data, 0)
- switch zxStatus(err) {
+ switch mxerror.Status(err) {
case zx.ErrOk:
return len(b), nil
case zx.ErrShouldWait:
@@ -246,179 +311,59 @@
}
}
-func (s *Socket) Seek(offset int64, whence int) (int64, error) {
- return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Seek"}
-}
-
-func (s *Socket) Open(path string, flags uint32, mode uint32) (fdio.FDIO, error) {
- return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Open"}
-}
-
-func (*Socket) Clone() ([]zx.Handle, error) {
- return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Clone"}
-}
-
// SetDgram marks a *Socket as a datagram (UDP) socket.
// A different protocol is used internally.
-func SetDgram(m fdio.FDIO) error {
- if m == nil {
- return errors.New("zxsocket.SetDgram: nil argument")
- }
- s, ok := m.(*Socket)
- if !ok {
- return errors.New("zxsocket.SetDgram: argument is not a *Socket")
- }
+func (s *Socket) SetDgram() {
s.dgram = true
- return nil
}
-// Bind is BSD Sockets bind on a *Socket.
-func Bind(m fdio.FDIO, addr mxnet.Addr, port uint16) error {
- if m == nil {
- return errors.New("zxsocket.Bind: nil argument")
- }
- b := make([]byte, mxnet.SockaddrLen)
- addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
- if err != nil {
- return err
- }
- b = b[:addrlen]
-
- s, ok := m.(*Socket)
- if !ok {
- return errors.New("zxsocket.Connect: argument is not a *Socket")
- }
- _, err = s.Misc(OpBind, 0, b, nil, nil)
- return err
-}
-
-// Connect is BSD Sockets connect on a *Socket.
-func Connect(m fdio.FDIO, addr mxnet.Addr, port uint16) error {
- if m == nil {
- return errors.New("zxsocket.Connect: nil argument")
- }
- b := make([]byte, mxnet.SockaddrLen)
- addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
- if err != nil {
- return err
- }
- b = b[:addrlen]
-
- s, ok := m.(*Socket)
- if !ok {
- return errors.New("zxsocket.Connect: argument is not a *Socket")
- }
- _, err = s.Misc(OpConnect, 0, b, nil, nil)
- if err != nil && zxStatus(err) == zx.ErrShouldWait {
- obs, err := s.Wait(mxnet.MXSIO_SIGNAL_OUTGOING, zx.TimensecInfinite)
- switch zxStatus(err) {
+func ReadControl(s zx.Socket, data []byte) (n int, err error) {
+ // c.f. zxsocket._read_control in zircon/system/ulib/fdio/remoteio.c
+ for {
+ n, err = s.Read(data, zx.SocketControl)
+ switch mxerror.Status(err) {
case zx.ErrOk:
- switch {
- case obs&mxnet.MXSIO_SIGNAL_CONNECTED != 0:
- return nil
+ return n, nil
+ case zx.ErrPeerClosed:
+ return 0, io.EOF
+ case zx.ErrShouldWait:
+ obs, err := zxwait.Wait(
+ zx.Handle(s),
+ zx.SignalSocketControlReadable|zx.SignalSocketPeerClosed,
+ zx.TimensecInfinite,
+ )
+ switch mxerror.Status(err) {
+ case zx.ErrOk:
+ switch {
+ case obs&zx.SignalSocketControlReadable != 0:
+ continue
+ case obs&zx.SignalSocketPeerClosed != 0:
+ return 0, io.EOF
+ }
+ case zx.ErrBadHandle, zx.ErrCanceled:
+ return 0, io.EOF
default:
- // TODO: Use opSetSockOpt to get the reason of the error.
- return errors.New("zxsocket.Connect: OpConnect was not successful")
+ return 0, err
}
default:
- return err
+ return 0, err
}
}
- return err
}
-func ListenStream(m fdio.FDIO, backlog int) error {
- if m == nil {
- return errors.New("zxsocket.ListenStream: nil argument")
- }
- s, ok := m.(*Socket)
- if !ok {
- return errors.New("zxsocket.ListenStream: argument is not a *Socket")
- }
- b := make([]byte, 4)
- b[0] = byte(backlog)
- b[1] = byte(backlog >> 8)
- b[2] = byte(backlog >> 16)
- b[3] = byte(backlog >> 24)
- _, err := s.Misc(OpListen, 0, b, nil, nil)
- return err
-}
-
-func Accept(m fdio.FDIO) (newm fdio.FDIO, err error) {
- if m == nil {
- return nil, errors.New("zxsocket.Accept: nil argument")
- }
- s, ok := m.(*Socket)
- if !ok {
- return nil, errors.New("zxsocket.Accept: argument is not a *Socket")
- }
- if s.flags&SocketFlagsDidListen == 0 {
- return nil, errors.New("zxsocket.Accept: listen was not called")
- }
-
- var h zx.Handle
+func WriteControl(s zx.Socket, data []byte) (int, error) {
+ // c.f. zxsocket._write_control
for {
- err = s.socket.Accept(&h)
- if err == nil {
- break
- }
- if zxStatus(err) != zx.ErrShouldWait {
- return nil, err
- }
- s.socket.Handle().SignalPeer(0, zx.SignalUser7)
- // TODO: non-blocking support, pass this to the poller
- const ZX_SOCKET_ACCEPT = zx.SignalSocketAccept
- const ZX_SOCKET_PEER_CLOSED = zx.SignalSocketPeerClosed
- pending, err := s.Wait(ZX_SOCKET_ACCEPT|ZX_SOCKET_PEER_CLOSED, zx.TimensecInfinite)
- if err != nil {
- return nil, err
- }
- if pending&ZX_SOCKET_ACCEPT != 0 {
+ n, err := s.Write(data, zx.SocketControl)
+ switch mxerror.Status(err) {
+ case zx.ErrOk:
+ return n, nil
+ case zx.ErrShouldWait:
+ _, err := zxwait.Wait(zx.Handle(s), zx.SignalSocketControlWriteable, zx.TimensecInfinite)
+ if err != nil {
+ return n, err
+ }
continue
}
- if pending&ZX_SOCKET_PEER_CLOSED != 0 {
- return nil, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket"}
- }
}
-
- return NewSocket(h)
-}
-
-func getName(m fdio.FDIO, op uint32, debug string) (addr mxnet.Addr, port uint16, err error) {
- if m == nil {
- return "", 0, errors.New("zxsocket." + debug + ": nil argument")
- }
- s, ok := m.(*Socket)
- if !ok {
- return "", 0, errors.New("zxsocket." + debug + ": argument is not a *Socket")
- }
- out := make([]byte, mxnet.SockaddrReplyLen)
- _, err = s.Misc(OpGetSockname, 0, nil, out, nil)
- if err != nil {
- return "", 0, err
- }
- addr, port, err = mxnet.DecodeSockaddr(out)
- if err != nil {
- return "", 0, err
- }
-
- return addr, port, nil
-}
-
-func GetSockName(m fdio.FDIO) (addr mxnet.Addr, port uint16, err error) {
- return getName(m, OpGetSockname, "GetSockName")
-}
-
-func GetPeerName(m fdio.FDIO) (addr mxnet.Addr, port uint16, err error) {
- return getName(m, OpGetPeerName, "GetPeerName")
-}
-
-func zxStatus(err error) zx.Status {
- if err == nil {
- return zx.ErrOk
- }
- if status, ok := err.(zx.Error); ok {
- return status.Status
- }
- return zx.ErrInternal
}