github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 "internal/poll" 9 "io" 10 "os" 11 "syscall" 12 ) 13 14 // Network file descriptor. 15 type netFD struct { 16 pfd poll.FD 17 18 // immutable until Close 19 net string 20 n string 21 dir string 22 listen, ctl, data *os.File 23 laddr, raddr Addr 24 isStream bool 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, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { 36 ret := &netFD{ 37 net: net, 38 n: name, 39 dir: netdir + "/" + net + "/" + name, 40 listen: listen, 41 ctl: ctl, data: data, 42 laddr: laddr, 43 raddr: raddr, 44 } 45 ret.pfd.Destroy = ret.destroy 46 return ret, nil 47 } 48 49 func (fd *netFD) init() error { 50 // stub for future fd.pd.Init(fd) 51 return nil 52 } 53 54 func (fd *netFD) name() string { 55 var ls, rs string 56 if fd.laddr != nil { 57 ls = fd.laddr.String() 58 } 59 if fd.raddr != nil { 60 rs = fd.raddr.String() 61 } 62 return fd.net + ":" + ls + "->" + rs 63 } 64 65 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } 66 67 func (fd *netFD) destroy() { 68 if !fd.ok() { 69 return 70 } 71 err := fd.ctl.Close() 72 if fd.data != nil { 73 if err1 := fd.data.Close(); err1 != nil && err == nil { 74 err = err1 75 } 76 } 77 if fd.listen != nil { 78 if err1 := fd.listen.Close(); err1 != nil && err == nil { 79 err = err1 80 } 81 } 82 fd.ctl = nil 83 fd.data = nil 84 fd.listen = nil 85 } 86 87 func (fd *netFD) Read(b []byte) (n int, err error) { 88 if !fd.ok() || fd.data == nil { 89 return 0, syscall.EINVAL 90 } 91 n, err = fd.pfd.Read(fd.data.Read, b) 92 if fd.net == "udp" && err == io.EOF { 93 n = 0 94 err = nil 95 } 96 return 97 } 98 99 func (fd *netFD) Write(b []byte) (n int, err error) { 100 if !fd.ok() || fd.data == nil { 101 return 0, syscall.EINVAL 102 } 103 return fd.pfd.Write(fd.data.Write, b) 104 } 105 106 func (fd *netFD) closeRead() error { 107 if !fd.ok() { 108 return syscall.EINVAL 109 } 110 return syscall.EPLAN9 111 } 112 113 func (fd *netFD) closeWrite() error { 114 if !fd.ok() { 115 return syscall.EINVAL 116 } 117 return syscall.EPLAN9 118 } 119 120 func (fd *netFD) Close() error { 121 if err := fd.pfd.Close(); err != nil { 122 return err 123 } 124 if !fd.ok() { 125 return syscall.EINVAL 126 } 127 if fd.net == "tcp" { 128 // The following line is required to unblock Reads. 129 _, err := fd.ctl.WriteString("close") 130 if err != nil { 131 return err 132 } 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 string) (*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 }