github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/net/fd_unix.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 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris 6 7 package net 8 9 import ( 10 "context" 11 "internal/poll" 12 "os" 13 "runtime" 14 "sync/atomic" 15 "syscall" 16 ) 17 18 // Network file descriptor. 19 type netFD struct { 20 pfd poll.FD 21 22 // immutable until Close 23 family int 24 sotype int 25 isConnected bool 26 net string 27 laddr Addr 28 raddr Addr 29 } 30 31 func newFD(sysfd, family, sotype int, net string) (*netFD, error) { 32 ret := &netFD{ 33 pfd: poll.FD{ 34 Sysfd: sysfd, 35 IsStream: sotype == syscall.SOCK_STREAM, 36 ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW, 37 }, 38 family: family, 39 sotype: sotype, 40 net: net, 41 } 42 return ret, nil 43 } 44 45 func (fd *netFD) init() error { 46 return fd.pfd.Init(fd.net, true) 47 } 48 49 func (fd *netFD) setAddr(laddr, raddr Addr) { 50 fd.laddr = laddr 51 fd.raddr = raddr 52 runtime.SetFinalizer(fd, (*netFD).Close) 53 } 54 55 func (fd *netFD) name() string { 56 var ls, rs string 57 if fd.laddr != nil { 58 ls = fd.laddr.String() 59 } 60 if fd.raddr != nil { 61 rs = fd.raddr.String() 62 } 63 return fd.net + ":" + ls + "->" + rs 64 } 65 66 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret error) { 67 // Do not need to call fd.writeLock here, 68 // because fd is not yet accessible to user, 69 // so no concurrent operations are possible. 70 switch err := connectFunc(fd.pfd.Sysfd, ra); err { 71 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: 72 case nil, syscall.EISCONN: 73 select { 74 case <-ctx.Done(): 75 return mapErr(ctx.Err()) 76 default: 77 } 78 if err := fd.pfd.Init(fd.net, true); err != nil { 79 return err 80 } 81 runtime.KeepAlive(fd) 82 return nil 83 case syscall.EINVAL: 84 // On Solaris we can see EINVAL if the socket has 85 // already been accepted and closed by the server. 86 // Treat this as a successful connection--writes to 87 // the socket will see EOF. For details and a test 88 // case in C see https://golang.org/issue/6828. 89 if runtime.GOOS == "solaris" { 90 return nil 91 } 92 fallthrough 93 default: 94 return os.NewSyscallError("connect", err) 95 } 96 if err := fd.pfd.Init(fd.net, true); err != nil { 97 return err 98 } 99 if deadline, _ := ctx.Deadline(); !deadline.IsZero() { 100 fd.pfd.SetWriteDeadline(deadline) 101 defer fd.pfd.SetWriteDeadline(noDeadline) 102 } 103 104 // Start the "interrupter" goroutine, if this context might be canceled. 105 // (The background context cannot) 106 // 107 // The interrupter goroutine waits for the context to be done and 108 // interrupts the dial (by altering the fd's write deadline, which 109 // wakes up waitWrite). 110 if ctx != context.Background() { 111 // Wait for the interrupter goroutine to exit before returning 112 // from connect. 113 done := make(chan struct{}) 114 interruptRes := make(chan error) 115 defer func() { 116 close(done) 117 if ctxErr := <-interruptRes; ctxErr != nil && ret == nil { 118 // The interrupter goroutine called SetWriteDeadline, 119 // but the connect code below had returned from 120 // waitWrite already and did a successful connect (ret 121 // == nil). Because we've now poisoned the connection 122 // by making it unwritable, don't return a successful 123 // dial. This was issue 16523. 124 ret = ctxErr 125 fd.Close() // prevent a leak 126 } 127 }() 128 go func() { 129 select { 130 case <-ctx.Done(): 131 // Force the runtime's poller to immediately give up 132 // waiting for writability, unblocking waitWrite 133 // below. 134 fd.pfd.SetWriteDeadline(aLongTimeAgo) 135 testHookCanceledDial() 136 interruptRes <- ctx.Err() 137 case <-done: 138 interruptRes <- nil 139 } 140 }() 141 } 142 143 for { 144 // Performing multiple connect system calls on a 145 // non-blocking socket under Unix variants does not 146 // necessarily result in earlier errors being 147 // returned. Instead, once runtime-integrated network 148 // poller tells us that the socket is ready, get the 149 // SO_ERROR socket option to see if the connection 150 // succeeded or failed. See issue 7474 for further 151 // details. 152 if err := fd.pfd.WaitWrite(); err != nil { 153 select { 154 case <-ctx.Done(): 155 return mapErr(ctx.Err()) 156 default: 157 } 158 return err 159 } 160 nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) 161 if err != nil { 162 return os.NewSyscallError("getsockopt", err) 163 } 164 switch err := syscall.Errno(nerr); err { 165 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: 166 case syscall.Errno(0), syscall.EISCONN: 167 if runtime.GOOS != "darwin" { 168 return nil 169 } 170 // See golang.org/issue/14548. 171 // On Darwin, multiple connect system calls on 172 // a non-blocking socket never harm SO_ERROR. 173 switch err := connectFunc(fd.pfd.Sysfd, ra); err { 174 case nil, syscall.EISCONN: 175 return nil 176 } 177 default: 178 return os.NewSyscallError("getsockopt", err) 179 } 180 runtime.KeepAlive(fd) 181 } 182 } 183 184 func (fd *netFD) Close() error { 185 runtime.SetFinalizer(fd, nil) 186 return fd.pfd.Close() 187 } 188 189 func (fd *netFD) shutdown(how int) error { 190 err := fd.pfd.Shutdown(how) 191 runtime.KeepAlive(fd) 192 return wrapSyscallError("shutdown", err) 193 } 194 195 func (fd *netFD) closeRead() error { 196 return fd.shutdown(syscall.SHUT_RD) 197 } 198 199 func (fd *netFD) closeWrite() error { 200 return fd.shutdown(syscall.SHUT_WR) 201 } 202 203 func (fd *netFD) Read(p []byte) (n int, err error) { 204 n, err = fd.pfd.Read(p) 205 runtime.KeepAlive(fd) 206 return n, wrapSyscallError("read", err) 207 } 208 209 func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { 210 n, sa, err = fd.pfd.ReadFrom(p) 211 runtime.KeepAlive(fd) 212 return n, sa, wrapSyscallError("recvfrom", err) 213 } 214 215 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { 216 n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob) 217 runtime.KeepAlive(fd) 218 return n, oobn, flags, sa, wrapSyscallError("recvmsg", err) 219 } 220 221 func (fd *netFD) Write(p []byte) (nn int, err error) { 222 nn, err = fd.pfd.Write(p) 223 runtime.KeepAlive(fd) 224 return nn, wrapSyscallError("write", err) 225 } 226 227 func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { 228 n, err = fd.pfd.WriteTo(p, sa) 229 runtime.KeepAlive(fd) 230 return n, wrapSyscallError("sendto", err) 231 } 232 233 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { 234 n, oobn, err = fd.pfd.WriteMsg(p, oob, sa) 235 runtime.KeepAlive(fd) 236 return n, oobn, wrapSyscallError("sendmsg", err) 237 } 238 239 func (fd *netFD) accept() (netfd *netFD, err error) { 240 d, rsa, errcall, err := fd.pfd.Accept() 241 if err != nil { 242 if errcall != "" { 243 err = wrapSyscallError(errcall, err) 244 } 245 return nil, err 246 } 247 248 if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil { 249 poll.CloseFunc(d) 250 return nil, err 251 } 252 if err = netfd.init(); err != nil { 253 fd.Close() 254 return nil, err 255 } 256 lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd) 257 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) 258 return netfd, nil 259 } 260 261 // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. 262 // If the kernel doesn't support it, this is set to 0. 263 var tryDupCloexec = int32(1) 264 265 func dupCloseOnExec(fd int) (newfd int, err error) { 266 if atomic.LoadInt32(&tryDupCloexec) == 1 { 267 r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0) 268 if runtime.GOOS == "darwin" && e1 == syscall.EBADF { 269 // On OS X 10.6 and below (but we only support 270 // >= 10.6), F_DUPFD_CLOEXEC is unsupported 271 // and fcntl there falls back (undocumented) 272 // to doing an ioctl instead, returning EBADF 273 // in this case because fd is not of the 274 // expected device fd type. Treat it as 275 // EINVAL instead, so we fall back to the 276 // normal dup path. 277 // TODO: only do this on 10.6 if we can detect 10.6 278 // cheaply. 279 e1 = syscall.EINVAL 280 } 281 switch e1 { 282 case 0: 283 return int(r0), nil 284 case syscall.EINVAL: 285 // Old kernel. Fall back to the portable way 286 // from now on. 287 atomic.StoreInt32(&tryDupCloexec, 0) 288 default: 289 return -1, os.NewSyscallError("fcntl", e1) 290 } 291 } 292 return dupCloseOnExecOld(fd) 293 } 294 295 // dupCloseOnExecUnixOld is the traditional way to dup an fd and 296 // set its O_CLOEXEC bit, using two system calls. 297 func dupCloseOnExecOld(fd int) (newfd int, err error) { 298 syscall.ForkLock.RLock() 299 defer syscall.ForkLock.RUnlock() 300 newfd, err = syscall.Dup(fd) 301 if err != nil { 302 return -1, os.NewSyscallError("dup", err) 303 } 304 syscall.CloseOnExec(newfd) 305 return 306 } 307 308 func (fd *netFD) dup() (f *os.File, err error) { 309 ns, err := dupCloseOnExec(fd.pfd.Sysfd) 310 if err != nil { 311 return nil, err 312 } 313 314 // We want blocking mode for the new fd, hence the double negative. 315 // This also puts the old fd into blocking mode, meaning that 316 // I/O will block the thread instead of letting us use the epoll server. 317 // Everything will still work, just with more threads. 318 if err = syscall.SetNonblock(ns, false); err != nil { 319 return nil, os.NewSyscallError("setnonblock", err) 320 } 321 322 return os.NewFile(uintptr(ns), fd.name()), nil 323 }