github.com/karrick/go@v0.0.0-20170817181416-d5b0ec858b37/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) (rsa 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 nil, mapErr(ctx.Err()) 76 default: 77 } 78 if err := fd.pfd.Init(fd.net, true); err != nil { 79 return nil, err 80 } 81 runtime.KeepAlive(fd) 82 return nil, 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, nil 91 } 92 fallthrough 93 default: 94 return nil, os.NewSyscallError("connect", err) 95 } 96 if err := fd.pfd.Init(fd.net, true); err != nil { 97 return nil, 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 nil, mapErr(ctx.Err()) 156 default: 157 } 158 return nil, err 159 } 160 nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) 161 if err != nil { 162 return nil, os.NewSyscallError("getsockopt", err) 163 } 164 switch err := syscall.Errno(nerr); err { 165 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: 166 case syscall.EISCONN: 167 return nil, nil 168 case syscall.Errno(0): 169 // The runtime poller can wake us up spuriously; 170 // see issues 14548 and 19289. Check that we are 171 // really connected; if not, wait again. 172 if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil { 173 return rsa, nil 174 } 175 default: 176 return nil, os.NewSyscallError("getsockopt", err) 177 } 178 runtime.KeepAlive(fd) 179 } 180 } 181 182 func (fd *netFD) Close() error { 183 runtime.SetFinalizer(fd, nil) 184 return fd.pfd.Close() 185 } 186 187 func (fd *netFD) shutdown(how int) error { 188 err := fd.pfd.Shutdown(how) 189 runtime.KeepAlive(fd) 190 return wrapSyscallError("shutdown", err) 191 } 192 193 func (fd *netFD) closeRead() error { 194 return fd.shutdown(syscall.SHUT_RD) 195 } 196 197 func (fd *netFD) closeWrite() error { 198 return fd.shutdown(syscall.SHUT_WR) 199 } 200 201 func (fd *netFD) Read(p []byte) (n int, err error) { 202 n, err = fd.pfd.Read(p) 203 runtime.KeepAlive(fd) 204 return n, wrapSyscallError("read", err) 205 } 206 207 func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { 208 n, sa, err = fd.pfd.ReadFrom(p) 209 runtime.KeepAlive(fd) 210 return n, sa, wrapSyscallError("recvfrom", err) 211 } 212 213 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { 214 n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob) 215 runtime.KeepAlive(fd) 216 return n, oobn, flags, sa, wrapSyscallError("recvmsg", err) 217 } 218 219 func (fd *netFD) Write(p []byte) (nn int, err error) { 220 nn, err = fd.pfd.Write(p) 221 runtime.KeepAlive(fd) 222 return nn, wrapSyscallError("write", err) 223 } 224 225 func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { 226 n, err = fd.pfd.WriteTo(p, sa) 227 runtime.KeepAlive(fd) 228 return n, wrapSyscallError("sendto", err) 229 } 230 231 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { 232 n, oobn, err = fd.pfd.WriteMsg(p, oob, sa) 233 runtime.KeepAlive(fd) 234 return n, oobn, wrapSyscallError("sendmsg", err) 235 } 236 237 func (fd *netFD) accept() (netfd *netFD, err error) { 238 d, rsa, errcall, err := fd.pfd.Accept() 239 if err != nil { 240 if errcall != "" { 241 err = wrapSyscallError(errcall, err) 242 } 243 return nil, err 244 } 245 246 if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil { 247 poll.CloseFunc(d) 248 return nil, err 249 } 250 if err = netfd.init(); err != nil { 251 fd.Close() 252 return nil, err 253 } 254 lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd) 255 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) 256 return netfd, nil 257 } 258 259 // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. 260 // If the kernel doesn't support it, this is set to 0. 261 var tryDupCloexec = int32(1) 262 263 func dupCloseOnExec(fd int) (newfd int, err error) { 264 if atomic.LoadInt32(&tryDupCloexec) == 1 { 265 r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0) 266 if runtime.GOOS == "darwin" && e1 == syscall.EBADF { 267 // On OS X 10.6 and below (but we only support 268 // >= 10.6), F_DUPFD_CLOEXEC is unsupported 269 // and fcntl there falls back (undocumented) 270 // to doing an ioctl instead, returning EBADF 271 // in this case because fd is not of the 272 // expected device fd type. Treat it as 273 // EINVAL instead, so we fall back to the 274 // normal dup path. 275 // TODO: only do this on 10.6 if we can detect 10.6 276 // cheaply. 277 e1 = syscall.EINVAL 278 } 279 switch e1 { 280 case 0: 281 return int(r0), nil 282 case syscall.EINVAL: 283 // Old kernel. Fall back to the portable way 284 // from now on. 285 atomic.StoreInt32(&tryDupCloexec, 0) 286 default: 287 return -1, os.NewSyscallError("fcntl", e1) 288 } 289 } 290 return dupCloseOnExecOld(fd) 291 } 292 293 // dupCloseOnExecUnixOld is the traditional way to dup an fd and 294 // set its O_CLOEXEC bit, using two system calls. 295 func dupCloseOnExecOld(fd int) (newfd int, err error) { 296 syscall.ForkLock.RLock() 297 defer syscall.ForkLock.RUnlock() 298 newfd, err = syscall.Dup(fd) 299 if err != nil { 300 return -1, os.NewSyscallError("dup", err) 301 } 302 syscall.CloseOnExec(newfd) 303 return 304 } 305 306 func (fd *netFD) dup() (f *os.File, err error) { 307 ns, err := dupCloseOnExec(fd.pfd.Sysfd) 308 if err != nil { 309 return nil, err 310 } 311 312 // We want blocking mode for the new fd, hence the double negative. 313 // This also puts the old fd into blocking mode, meaning that 314 // I/O will block the thread instead of letting us use the epoll server. 315 // Everything will still work, just with more threads. 316 if err = syscall.SetNonblock(ns, false); err != nil { 317 return nil, os.NewSyscallError("setnonblock", err) 318 } 319 320 return os.NewFile(uintptr(ns), fd.name()), nil 321 }