blob: 606daa06ba5dbf9eaea10185298e9fffb65feb08 [file] [log] [blame]
// Copyright 2016 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.
package net
import (
"errors"
"os"
"runtime"
"syscall"
"syscall/zx/mxnet"
"syscall/zx/zxsocket"
"time"
)
// Network file descriptor.
type netFD struct {
// locking/lifetime of sysfd + serialize access to Read and Write methods
fdmu fdMutex
sock *zxsocket.Socket
// immutable until Close
net string
family int
sotype int
isStream bool
isConnected bool
laddr Addr
raddr Addr
}
func (fd *netFD) destroy() {
panic("TODO")
}
func sysInit() {
}
func (fd *netFD) isTCP() bool {
return len(fd.net) >= 3 && fd.net[:3] == "tcp"
}
func (fd *netFD) Read(b []byte) (n int, err error) {
return fd.sock.Read(b)
}
func (fd *netFD) Write(b []byte) (n int, err error) {
// The Go std library expects that writes must return either an error or a full
// write, however, this is not the pattern used in Zircon or FDIO. We implement
// that behavior here:
l, t := len(b), 0
for {
n, err := fd.sock.Write(b)
t += n
if t == l {
return t, err
}
if err != nil {
return t, err
}
// If the total is not all of the requested data to be written, and there's no
// error, we loop and write again.
b = b[n:]
}
}
func (fd *netFD) recvMsg(b []byte) (n, flags int, addr string, port uint16, err error) {
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.sock.SendMsg(b, addr, port)
}
func (fd *netFD) closeRead() error {
return errors.New("net: closeRead not implemented on fuchsia")
}
func (fd *netFD) closeWrite() error {
return errors.New("net: closeWrite not implemented on fuchsia")
}
func (fd *netFD) Close() error {
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")
}
func (fd *netFD) setDeadline(t time.Time) error {
return errors.New("net: setDeadline not implemented on fuchsia")
}
func (fd *netFD) setReadDeadline(t time.Time) error {
return errors.New("net: setReadDeadline not implemented on fuchsia")
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
return errors.New("net: setWriteDeadline not implemented on fuchsia")
}
func (fd *netFD) accept() (netfd *netFD, err error) {
if err := fd.readLock(); err != nil {
return nil, err
}
defer fd.readUnlock()
sock, err := fd.sock.Accept()
if err != nil {
return nil, err
}
netfd = &netFD{
sock: sock,
family: fd.family,
sotype: fd.sotype,
net: fd.net,
}
netfd.setAddr()
return netfd, nil
}
func (fd *netFD) asAddr(ipAddr mxnet.Addr, port uint16, err error) sockaddr {
if err != nil {
return nil
}
ip := IP(ipAddr)
if isZeros(ip) && port == 0 {
return nil
}
switch fd.sotype {
case syscall.SOCK_STREAM:
return &TCPAddr{IP: ip, Port: int(port)}
case syscall.SOCK_DGRAM:
return &UDPAddr{IP: ip, Port: int(port)}
}
return nil
}
func (fd *netFD) setAddr() {
fd.laddr = fd.asAddr(fd.sock.SockName())
fd.raddr = fd.asAddr(fd.sock.PeerName())
runtime.SetFinalizer(fd, (*netFD).Close)
}