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 5package net 6 7import ( 8 "internal/poll" 9 "io" 10 "os" 11 "syscall" 12) 13 14// Network file descriptor. 15type 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 27var netdir = "/net" // default network 28 29func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { 30 ret := &netFD{ 31 net: net, 32 n: name, 33 dir: netdir + "/" + net + "/" + name, 34 listen: listen, 35 ctl: ctl, data: data, 36 laddr: laddr, 37 raddr: raddr, 38 } 39 ret.pfd.Destroy = ret.destroy 40 return ret, nil 41} 42 43func (fd *netFD) init() error { 44 // stub for future fd.pd.Init(fd) 45 return nil 46} 47 48func (fd *netFD) name() string { 49 var ls, rs string 50 if fd.laddr != nil { 51 ls = fd.laddr.String() 52 } 53 if fd.raddr != nil { 54 rs = fd.raddr.String() 55 } 56 return fd.net + ":" + ls + "->" + rs 57} 58 59func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } 60 61func (fd *netFD) destroy() { 62 if !fd.ok() { 63 return 64 } 65 err := fd.ctl.Close() 66 if fd.data != nil { 67 if err1 := fd.data.Close(); err1 != nil && err == nil { 68 err = err1 69 } 70 } 71 if fd.listen != nil { 72 if err1 := fd.listen.Close(); err1 != nil && err == nil { 73 err = err1 74 } 75 } 76 fd.ctl = nil 77 fd.data = nil 78 fd.listen = nil 79} 80 81func (fd *netFD) Read(b []byte) (n int, err error) { 82 if !fd.ok() || fd.data == nil { 83 return 0, syscall.EINVAL 84 } 85 n, err = fd.pfd.Read(fd.data.Read, b) 86 if fd.net == "udp" && err == io.EOF { 87 n = 0 88 err = nil 89 } 90 return 91} 92 93func (fd *netFD) Write(b []byte) (n int, err error) { 94 if !fd.ok() || fd.data == nil { 95 return 0, syscall.EINVAL 96 } 97 return fd.pfd.Write(fd.data.Write, b) 98} 99 100func (fd *netFD) closeRead() error { 101 if !fd.ok() { 102 return syscall.EINVAL 103 } 104 return syscall.EPLAN9 105} 106 107func (fd *netFD) closeWrite() error { 108 if !fd.ok() { 109 return syscall.EINVAL 110 } 111 return syscall.EPLAN9 112} 113 114func (fd *netFD) Close() error { 115 if err := fd.pfd.Close(); err != nil { 116 return err 117 } 118 if !fd.ok() { 119 return syscall.EINVAL 120 } 121 if fd.net == "tcp" { 122 // The following line is required to unblock Reads. 123 _, err := fd.ctl.WriteString("close") 124 if err != nil { 125 return err 126 } 127 } 128 err := fd.ctl.Close() 129 if fd.data != nil { 130 if err1 := fd.data.Close(); err1 != nil && err == nil { 131 err = err1 132 } 133 } 134 if fd.listen != nil { 135 if err1 := fd.listen.Close(); err1 != nil && err == nil { 136 err = err1 137 } 138 } 139 fd.ctl = nil 140 fd.data = nil 141 fd.listen = nil 142 return err 143} 144 145// This method is only called via Conn. 146func (fd *netFD) dup() (*os.File, error) { 147 if !fd.ok() || fd.data == nil { 148 return nil, syscall.EINVAL 149 } 150 return fd.file(fd.data, fd.dir+"/data") 151} 152 153func (l *TCPListener) dup() (*os.File, error) { 154 if !l.fd.ok() { 155 return nil, syscall.EINVAL 156 } 157 return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl") 158} 159 160func (fd *netFD) file(f *os.File, s string) (*os.File, error) { 161 dfd, err := syscall.Dup(int(f.Fd()), -1) 162 if err != nil { 163 return nil, os.NewSyscallError("dup", err) 164 } 165 return os.NewFile(uintptr(dfd), s), nil 166} 167 168func setReadBuffer(fd *netFD, bytes int) error { 169 return syscall.EPLAN9 170} 171 172func setWriteBuffer(fd *netFD, bytes int) error { 173 return syscall.EPLAN9 174} 175