github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/net/fd_plan9.go (about)

     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  	"io"
     9  	"os"
    10  	"syscall"
    11  	"time"
    12  )
    13  
    14  // Network file descriptor.
    15  type netFD struct {
    16  	// locking/lifetime of sysfd + serialize access to Read and Write methods
    17  	fdmu fdMutex
    18  
    19  	// immutable until Close
    20  	net          string
    21  	n            string
    22  	dir          string
    23  	ctl, data    *os.File
    24  	laddr, raddr Addr
    25  }
    26  
    27  var (
    28  	netdir string // default network
    29  )
    30  
    31  func sysInit() {
    32  	netdir = "/net"
    33  }
    34  
    35  func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
    36  	return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
    37  }
    38  
    39  func (fd *netFD) init() error {
    40  	// stub for future fd.pd.Init(fd)
    41  	return nil
    42  }
    43  
    44  func (fd *netFD) name() string {
    45  	var ls, rs string
    46  	if fd.laddr != nil {
    47  		ls = fd.laddr.String()
    48  	}
    49  	if fd.raddr != nil {
    50  		rs = fd.raddr.String()
    51  	}
    52  	return fd.net + ":" + ls + "->" + rs
    53  }
    54  
    55  func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
    56  
    57  func (fd *netFD) destroy() {
    58  	if !fd.ok() {
    59  		return
    60  	}
    61  	err := fd.ctl.Close()
    62  	if fd.data != nil {
    63  		if err1 := fd.data.Close(); err1 != nil && err == nil {
    64  			err = err1
    65  		}
    66  	}
    67  	fd.ctl = nil
    68  	fd.data = nil
    69  }
    70  
    71  func (fd *netFD) Read(b []byte) (n int, err error) {
    72  	if !fd.ok() || fd.data == nil {
    73  		return 0, syscall.EINVAL
    74  	}
    75  	if err := fd.readLock(); err != nil {
    76  		return 0, err
    77  	}
    78  	defer fd.readUnlock()
    79  	if len(b) == 0 {
    80  		return 0, nil
    81  	}
    82  	n, err = fd.data.Read(b)
    83  	if isHangup(err) {
    84  		err = io.EOF
    85  	}
    86  	if fd.net == "udp" && err == io.EOF {
    87  		n = 0
    88  		err = nil
    89  	}
    90  	return
    91  }
    92  
    93  func (fd *netFD) Write(b []byte) (n int, err error) {
    94  	if !fd.ok() || fd.data == nil {
    95  		return 0, syscall.EINVAL
    96  	}
    97  	if err := fd.writeLock(); err != nil {
    98  		return 0, err
    99  	}
   100  	defer fd.writeUnlock()
   101  	return fd.data.Write(b)
   102  }
   103  
   104  func (fd *netFD) closeRead() error {
   105  	if !fd.ok() {
   106  		return syscall.EINVAL
   107  	}
   108  	return syscall.EPLAN9
   109  }
   110  
   111  func (fd *netFD) closeWrite() error {
   112  	if !fd.ok() {
   113  		return syscall.EINVAL
   114  	}
   115  	return syscall.EPLAN9
   116  }
   117  
   118  func (fd *netFD) Close() error {
   119  	if !fd.fdmu.increfAndClose() {
   120  		return errClosing
   121  	}
   122  	if !fd.ok() {
   123  		return syscall.EINVAL
   124  	}
   125  	if fd.net == "tcp" {
   126  		// The following line is required to unblock Reads.
   127  		// For some reason, WriteString returns an error:
   128  		// "write /net/tcp/39/listen: inappropriate use of fd"
   129  		// But without it, Reads on dead conns hang forever.
   130  		// See Issue 9554.
   131  		fd.ctl.WriteString("hangup")
   132  	}
   133  	err := fd.ctl.Close()
   134  	if fd.data != nil {
   135  		if err1 := fd.data.Close(); err1 != nil && err == nil {
   136  			err = err1
   137  		}
   138  	}
   139  	fd.ctl = nil
   140  	fd.data = nil
   141  	return err
   142  }
   143  
   144  // This method is only called via Conn.
   145  func (fd *netFD) dup() (*os.File, error) {
   146  	if !fd.ok() || fd.data == nil {
   147  		return nil, syscall.EINVAL
   148  	}
   149  	return fd.file(fd.data, fd.dir+"/data")
   150  }
   151  
   152  func (l *TCPListener) dup() (*os.File, error) {
   153  	if !l.fd.ok() {
   154  		return nil, syscall.EINVAL
   155  	}
   156  	return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl")
   157  }
   158  
   159  func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
   160  	dfd, err := syscall.Dup(int(f.Fd()), -1)
   161  	if err != nil {
   162  		return nil, os.NewSyscallError("dup", err)
   163  	}
   164  	return os.NewFile(uintptr(dfd), s), nil
   165  }
   166  
   167  func (fd *netFD) setDeadline(t time.Time) error {
   168  	return syscall.EPLAN9
   169  }
   170  
   171  func (fd *netFD) setReadDeadline(t time.Time) error {
   172  	return syscall.EPLAN9
   173  }
   174  
   175  func (fd *netFD) setWriteDeadline(t time.Time) error {
   176  	return syscall.EPLAN9
   177  }
   178  
   179  func setReadBuffer(fd *netFD, bytes int) error {
   180  	return syscall.EPLAN9
   181  }
   182  
   183  func setWriteBuffer(fd *netFD, bytes int) error {
   184  	return syscall.EPLAN9
   185  }
   186  
   187  func isHangup(err error) bool {
   188  	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
   189  }