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 }