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