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 "time" 13) 14 15// Network file descriptor. 16type netFD struct { 17 pfd poll.FD 18 19 // immutable until Close 20 net string 21 n string 22 dir string 23 listen, ctl, data *os.File 24 laddr, raddr Addr 25 isStream bool 26} 27 28var netdir = "/net" // default network 29 30func newFD(net, name string, 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 44func (fd *netFD) init() error { 45 // stub for future fd.pd.Init(fd) 46 return nil 47} 48 49func (fd *netFD) name() string { 50 var ls, rs string 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 60func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } 61 62func (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 82func (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 94func (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 101func (fd *netFD) closeRead() error { 102 if !fd.ok() { 103 return syscall.EINVAL 104 } 105 return syscall.EPLAN9 106} 107 108func (fd *netFD) closeWrite() error { 109 if !fd.ok() { 110 return syscall.EINVAL 111 } 112 return syscall.EPLAN9 113} 114 115func (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 err := fd.ctl.Close() 130 if fd.data != nil { 131 if err1 := fd.data.Close(); err1 != nil && err == nil { 132 err = err1 133 } 134 } 135 if fd.listen != nil { 136 if err1 := fd.listen.Close(); err1 != nil && err == nil { 137 err = err1 138 } 139 } 140 fd.ctl = nil 141 fd.data = nil 142 fd.listen = nil 143 return err 144} 145 146// This method is only called via Conn. 147func (fd *netFD) dup() (*os.File, error) { 148 if !fd.ok() || fd.data == nil { 149 return nil, syscall.EINVAL 150 } 151 return fd.file(fd.data, fd.dir+"/data") 152} 153 154func (l *TCPListener) dup() (*os.File, error) { 155 if !l.fd.ok() { 156 return nil, syscall.EINVAL 157 } 158 return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl") 159} 160 161func (fd *netFD) file(f *os.File, s string) (*os.File, error) { 162 dfd, err := syscall.Dup(int(f.Fd()), -1) 163 if err != nil { 164 return nil, os.NewSyscallError("dup", err) 165 } 166 return os.NewFile(uintptr(dfd), s), nil 167} 168 169func setReadBuffer(fd *netFD, bytes int) error { 170 return syscall.EPLAN9 171} 172 173func setWriteBuffer(fd *netFD, bytes int) error { 174 return syscall.EPLAN9 175} 176 177func (fd *netFD) SetDeadline(t time.Time) error { 178 return fd.pfd.SetDeadline(t) 179} 180 181func (fd *netFD) SetReadDeadline(t time.Time) error { 182 return fd.pfd.SetReadDeadline(t) 183} 184 185func (fd *netFD) SetWriteDeadline(t time.Time) error { 186 return fd.pfd.SetWriteDeadline(t) 187} 188