fd_unix.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
  5. package net
  6. import (
  7. "context"
  8. "internal/poll"
  9. "os"
  10. "runtime"
  11. "syscall"
  12. )
  13. const (
  14. readSyscallName = "read"
  15. readFromSyscallName = "recvfrom"
  16. readMsgSyscallName = "recvmsg"
  17. writeSyscallName = "write"
  18. writeToSyscallName = "sendto"
  19. writeMsgSyscallName = "sendmsg"
  20. )
  21. func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
  22. ret := &netFD{
  23. pfd: poll.FD{
  24. Sysfd: sysfd,
  25. IsStream: sotype == syscall.SOCK_STREAM,
  26. ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
  27. },
  28. family: family,
  29. sotype: sotype,
  30. net: net,
  31. }
  32. return ret, nil
  33. }
  34. func (fd *netFD) init() error {
  35. return fd.pfd.Init(fd.net, true)
  36. }
  37. func (fd *netFD) name() string {
  38. var ls, rs string
  39. if fd.laddr != nil {
  40. ls = fd.laddr.String()
  41. }
  42. if fd.raddr != nil {
  43. rs = fd.raddr.String()
  44. }
  45. return fd.net + ":" + ls + "->" + rs
  46. }
  47. func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
  48. // Do not need to call fd.writeLock here,
  49. // because fd is not yet accessible to user,
  50. // so no concurrent operations are possible.
  51. switch err := connectFunc(fd.pfd.Sysfd, ra); err {
  52. case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
  53. case nil, syscall.EISCONN:
  54. select {
  55. case <-ctx.Done():
  56. return nil, mapErr(ctx.Err())
  57. default:
  58. }
  59. if err := fd.pfd.Init(fd.net, true); err != nil {
  60. return nil, err
  61. }
  62. runtime.KeepAlive(fd)
  63. return nil, nil
  64. case syscall.EINVAL:
  65. // On Solaris and illumos we can see EINVAL if the socket has
  66. // already been accepted and closed by the server. Treat this
  67. // as a successful connection--writes to the socket will see
  68. // EOF. For details and a test case in C see
  69. // https://golang.org/issue/6828.
  70. if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
  71. return nil, nil
  72. }
  73. fallthrough
  74. default:
  75. return nil, os.NewSyscallError("connect", err)
  76. }
  77. if err := fd.pfd.Init(fd.net, true); err != nil {
  78. return nil, err
  79. }
  80. if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
  81. fd.pfd.SetWriteDeadline(deadline)
  82. defer fd.pfd.SetWriteDeadline(noDeadline)
  83. }
  84. // Start the "interrupter" goroutine, if this context might be canceled.
  85. //
  86. // The interrupter goroutine waits for the context to be done and
  87. // interrupts the dial (by altering the fd's write deadline, which
  88. // wakes up waitWrite).
  89. ctxDone := ctx.Done()
  90. if ctxDone != nil {
  91. // Wait for the interrupter goroutine to exit before returning
  92. // from connect.
  93. done := make(chan struct{})
  94. interruptRes := make(chan error)
  95. defer func() {
  96. close(done)
  97. if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
  98. // The interrupter goroutine called SetWriteDeadline,
  99. // but the connect code below had returned from
  100. // waitWrite already and did a successful connect (ret
  101. // == nil). Because we've now poisoned the connection
  102. // by making it unwritable, don't return a successful
  103. // dial. This was issue 16523.
  104. ret = mapErr(ctxErr)
  105. fd.Close() // prevent a leak
  106. }
  107. }()
  108. go func() {
  109. select {
  110. case <-ctxDone:
  111. // Force the runtime's poller to immediately give up
  112. // waiting for writability, unblocking waitWrite
  113. // below.
  114. fd.pfd.SetWriteDeadline(aLongTimeAgo)
  115. testHookCanceledDial()
  116. interruptRes <- ctx.Err()
  117. case <-done:
  118. interruptRes <- nil
  119. }
  120. }()
  121. }
  122. for {
  123. // Performing multiple connect system calls on a
  124. // non-blocking socket under Unix variants does not
  125. // necessarily result in earlier errors being
  126. // returned. Instead, once runtime-integrated network
  127. // poller tells us that the socket is ready, get the
  128. // SO_ERROR socket option to see if the connection
  129. // succeeded or failed. See issue 7474 for further
  130. // details.
  131. if err := fd.pfd.WaitWrite(); err != nil {
  132. select {
  133. case <-ctxDone:
  134. return nil, mapErr(ctx.Err())
  135. default:
  136. }
  137. return nil, err
  138. }
  139. nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
  140. if err != nil {
  141. return nil, os.NewSyscallError("getsockopt", err)
  142. }
  143. switch err := syscall.Errno(nerr); err {
  144. case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
  145. case syscall.EISCONN:
  146. return nil, nil
  147. case syscall.Errno(0):
  148. // The runtime poller can wake us up spuriously;
  149. // see issues 14548 and 19289. Check that we are
  150. // really connected; if not, wait again.
  151. if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
  152. return rsa, nil
  153. }
  154. default:
  155. return nil, os.NewSyscallError("connect", err)
  156. }
  157. runtime.KeepAlive(fd)
  158. }
  159. }
  160. func (fd *netFD) accept() (netfd *netFD, err error) {
  161. d, rsa, errcall, err := fd.pfd.Accept()
  162. if err != nil {
  163. if errcall != "" {
  164. err = wrapSyscallError(errcall, err)
  165. }
  166. return nil, err
  167. }
  168. if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
  169. poll.CloseFunc(d)
  170. return nil, err
  171. }
  172. if err = netfd.init(); err != nil {
  173. netfd.Close()
  174. return nil, err
  175. }
  176. lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
  177. netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
  178. return netfd, nil
  179. }
  180. func (fd *netFD) dup() (f *os.File, err error) {
  181. ns, call, err := fd.pfd.Dup()
  182. if err != nil {
  183. if call != "" {
  184. err = os.NewSyscallError(call, err)
  185. }
  186. return nil, err
  187. }
  188. return os.NewFile(uintptr(ns), fd.name()), nil
  189. }