blob: 6018f75720e46906dce728aaaca6db75a52e8778 [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.
//+build fuchsia
// TODO: move to using fd_unix for fuchsia?
package net
import (
"errors"
"fmt"
"internal/poll"
"os"
"runtime"
"syscall"
"syscall/zx/net"
"syscall/zx/posix/socket"
"syscall/zx/zxsocket"
"time"
)
// Network file descriptor.
type netFD struct {
pfd poll.FD
// immutable until Close
sock zxsocket.Socket
net string
family int
isConnected bool
laddr Addr
raddr Addr
}
func domainToFamily(domain socket.Domain) int {
switch domain {
case socket.DomainIpv4:
return syscall.AF_INET
case socket.DomainIpv6:
return syscall.AF_INET6
default:
panic(fmt.Sprintf("unrecognized socket domain %s(%d)", domain, domain))
}
}
func familyToDomain(family int) socket.Domain {
switch family {
case syscall.AF_INET:
return socket.DomainIpv4
case syscall.AF_INET6:
return socket.DomainIpv6
default:
panic(fmt.Sprintf("unrecognized socket family %d", family))
}
}
func newFD(sock zxsocket.Socket, domain socket.Domain, net string) *netFD {
return &netFD{
pfd: poll.FD{
Sysfd: syscall.OpenFDIO(sock),
},
sock: sock,
family: domainToFamily(domain),
net: net,
}
}
func (fd *netFD) init() error {
// TODO: flip to true after implementing netpoller for real
return fd.pfd.Init(fd.net, false)
}
func (fd *netFD) isTCP() bool {
return len(fd.net) >= 3 && fd.net[:3] == "tcp"
}
func (fd *netFD) Read(b []byte) (n int, err error) {
n, err = fd.pfd.Read(b)
runtime.KeepAlive(fd)
return n, err
}
func (fd *netFD) Write(b []byte) (n int, err error) {
n, err = fd.pfd.Write(b)
runtime.KeepAlive(fd)
return n, err
}
func (fd *netFD) readMsg(b []byte) (n, flags int, addr net.SocketAddress, err error) {
// TODO: move call to pfd
data, addr, err := fd.sock.(*zxsocket.DatagramSocket).RecvMsg(len(b))
runtime.KeepAlive(fd)
n = copy(b, data)
return n, 0, addr, err
}
func (fd *netFD) sendMsg(b []byte, addr net.SocketAddress) (n int, err error) {
// TODO: move call to pfd
n, err = fd.sock.(*zxsocket.DatagramSocket).SendMsg(b, addr)
runtime.KeepAlive(fd)
return n, err
}
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.pfd.Close()
}
func (fd *netFD) dup() (*os.File, error) {
fdio, err := fd.sock.Clone()
if err != nil {
return nil, err
}
return os.NewFile(uintptr(syscall.OpenFDIO(fdio)), fd.name()), nil
}
func (fd *netFD) accept() (*netFD, error) {
newm, err := fd.pfd.Accept()
if err != nil {
return nil, err
}
netfd := newFD(newm, familyToDomain(fd.family), fd.net)
if err := netfd.init(); err != nil {
fd.Close()
return nil, err
}
netfd.setAddr()
return netfd, nil
}
func socketAddrToIpPort(addr net.SocketAddress) (IP, int) {
switch addr.Which() {
case net.SocketAddressIpv4:
return addr.Ipv4.Address.Addr[:], int(addr.Ipv4.Port)
case net.SocketAddressIpv6:
return addr.Ipv6.Address.Addr[:], int(addr.Ipv6.Port)
default:
panic(fmt.Sprintf("unrecognized SocketAddress variant %d", addr.Which()))
}
}
func (fd *netFD) asAddr(addr net.SocketAddress, err error) sockaddr {
if err != nil {
return nil
}
ip, port := socketAddrToIpPort(addr)
if isZeros(ip) && port == 0 {
return nil
}
switch fd.sock.(type) {
case *zxsocket.DatagramSocket:
return &UDPAddr{IP: ip, Port: port}
case *zxsocket.StreamSocket:
return &TCPAddr{IP: ip, Port: port}
default:
panic(fmt.Sprintf("unrecognized socket type %T", fd.sock))
}
}
func (fd *netFD) setAddr() {
fd.laddr = fd.asAddr(fd.sock.GetSockName())
fd.raddr = fd.asAddr(fd.sock.GetPeerName())
runtime.SetFinalizer(fd, (*netFD).Close)
}
func (fd *netFD) name() string {
var ls, rs string
if fd.laddr != nil {
ls = fd.laddr.String()
}
if fd.raddr != nil {
rs = fd.raddr.String()
}
return fd.net + ":" + ls + "->" + rs
}
func (fd *netFD) SetDeadline(t time.Time) error {
return fd.pfd.SetDeadline(t)
}
func (fd *netFD) SetReadDeadline(t time.Time) error {
return fd.pfd.SetReadDeadline(t)
}
func (fd *netFD) SetWriteDeadline(t time.Time) error {
return fd.pfd.SetWriteDeadline(t)
}