fd_plan9.mx raw

   1  // Copyright 2009 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package net
   6  
   7  import (
   8  	"internal/poll"
   9  	"io"
  10  	"os"
  11  	"syscall"
  12  	"time"
  13  )
  14  
  15  // Network file descriptor.
  16  type netFD struct {
  17  	pfd poll.FD
  18  
  19  	// immutable until Close
  20  	net               []byte
  21  	n                 []byte
  22  	dir               []byte
  23  	listen, ctl, data *os.File
  24  	laddr, raddr      Addr
  25  	isStream          bool
  26  }
  27  
  28  var netdir = "/net" // default network
  29  
  30  func newFD(net, name []byte, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
  31  	ret := &netFD{
  32  		net:    net,
  33  		n:      name,
  34  		dir:    netdir + "/" + net + "/" + name,
  35  		listen: listen,
  36  		ctl:    ctl, data: data,
  37  		laddr: laddr,
  38  		raddr: raddr,
  39  	}
  40  	ret.pfd.Destroy = ret.destroy
  41  	return ret, nil
  42  }
  43  
  44  func (fd *netFD) init() error {
  45  	// stub for future fd.pd.Init(fd)
  46  	return nil
  47  }
  48  
  49  func (fd *netFD) name() []byte {
  50  	var ls, rs []byte
  51  	if fd.laddr != nil {
  52  		ls = fd.laddr.String()
  53  	}
  54  	if fd.raddr != nil {
  55  		rs = fd.raddr.String()
  56  	}
  57  	return fd.net + ":" + ls + "->" + rs
  58  }
  59  
  60  func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
  61  
  62  func (fd *netFD) destroy() {
  63  	if !fd.ok() {
  64  		return
  65  	}
  66  	err := fd.ctl.Close()
  67  	if fd.data != nil {
  68  		if err1 := fd.data.Close(); err1 != nil && err == nil {
  69  			err = err1
  70  		}
  71  	}
  72  	if fd.listen != nil {
  73  		if err1 := fd.listen.Close(); err1 != nil && err == nil {
  74  			err = err1
  75  		}
  76  	}
  77  	fd.ctl = nil
  78  	fd.data = nil
  79  	fd.listen = nil
  80  }
  81  
  82  func (fd *netFD) Read(b []byte) (n int, err error) {
  83  	if !fd.ok() || fd.data == nil {
  84  		return 0, syscall.EINVAL
  85  	}
  86  	n, err = fd.pfd.Read(fd.data.Read, b)
  87  	if fd.net == "udp" && err == io.EOF {
  88  		n = 0
  89  		err = nil
  90  	}
  91  	return
  92  }
  93  
  94  func (fd *netFD) Write(b []byte) (n int, err error) {
  95  	if !fd.ok() || fd.data == nil {
  96  		return 0, syscall.EINVAL
  97  	}
  98  	return fd.pfd.Write(fd.data.Write, b)
  99  }
 100  
 101  func (fd *netFD) closeRead() error {
 102  	if !fd.ok() {
 103  		return syscall.EINVAL
 104  	}
 105  	return syscall.EPLAN9
 106  }
 107  
 108  func (fd *netFD) closeWrite() error {
 109  	if !fd.ok() {
 110  		return syscall.EINVAL
 111  	}
 112  	return syscall.EPLAN9
 113  }
 114  
 115  func (fd *netFD) Close() error {
 116  	if err := fd.pfd.Close(); err != nil {
 117  		return err
 118  	}
 119  	if !fd.ok() {
 120  		return syscall.EINVAL
 121  	}
 122  	if fd.net == "tcp" {
 123  		// The following line is required to unblock Reads.
 124  		_, err := fd.ctl.WriteString("close")
 125  		if err != nil {
 126  			return err
 127  		}
 128  	}
 129  	if fd.net == "udp" {
 130  		// The following line is required to unblock Reads.
 131  		// See https://go.dev/issue/72770.
 132  		fd.SetReadDeadline(time.Now().Add(-time.Hour))
 133  	}
 134  	err := fd.ctl.Close()
 135  	if fd.data != nil {
 136  		if err1 := fd.data.Close(); err1 != nil && err == nil {
 137  			err = err1
 138  		}
 139  	}
 140  	if fd.listen != nil {
 141  		if err1 := fd.listen.Close(); err1 != nil && err == nil {
 142  			err = err1
 143  		}
 144  	}
 145  	fd.ctl = nil
 146  	fd.data = nil
 147  	fd.listen = nil
 148  	return err
 149  }
 150  
 151  // This method is only called via Conn.
 152  func (fd *netFD) dup() (*os.File, error) {
 153  	if !fd.ok() || fd.data == nil {
 154  		return nil, syscall.EINVAL
 155  	}
 156  	return fd.file(fd.data, fd.dir+"/data")
 157  }
 158  
 159  func (l *TCPListener) dup() (*os.File, error) {
 160  	if !l.fd.ok() {
 161  		return nil, syscall.EINVAL
 162  	}
 163  	return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl")
 164  }
 165  
 166  func (fd *netFD) file(f *os.File, s []byte) (*os.File, error) {
 167  	dfd, err := syscall.Dup(int(f.Fd()), -1)
 168  	if err != nil {
 169  		return nil, os.NewSyscallError("dup", err)
 170  	}
 171  	return os.NewFile(uintptr(dfd), s), nil
 172  }
 173  
 174  func setReadBuffer(fd *netFD, bytes int) error {
 175  	return syscall.EPLAN9
 176  }
 177  
 178  func setWriteBuffer(fd *netFD, bytes int) error {
 179  	return syscall.EPLAN9
 180  }
 181  
 182  func (fd *netFD) SetDeadline(t time.Time) error {
 183  	return fd.pfd.SetDeadline(t)
 184  }
 185  
 186  func (fd *netFD) SetReadDeadline(t time.Time) error {
 187  	return fd.pfd.SetReadDeadline(t)
 188  }
 189  
 190  func (fd *netFD) SetWriteDeadline(t time.Time) error {
 191  	return fd.pfd.SetWriteDeadline(t)
 192  }
 193