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.
18 readSyscallName = "read"
19 readFromSyscallName = "recvfrom"
20 readMsgSyscallName = "recvmsg"
21 writeSyscallName = "write"
22 writeToSyscallName = "sendto"
23 writeMsgSyscallName = "sendmsg"
26 func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
30 IsStream: sotype == syscall.SOCK_STREAM,
31 ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
40 func (fd *netFD) init() error {
41 return fd.pfd.Init(fd.net, true)
44 func (fd *netFD) name() string {
47 ls = fd.laddr.String()
50 rs = fd.raddr.String()
52 return fd.net + ":" + ls + "->" + rs
55 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
56 // Do not need to call fd.writeLock here,
57 // because fd is not yet accessible to user,
58 // so no concurrent operations are possible.
59 switch err := connectFunc(fd.pfd.Sysfd, ra); err {
60 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
61 case nil, syscall.EISCONN:
64 return nil, mapErr(ctx.Err())
67 if err := fd.pfd.Init(fd.net, true); err != nil {
73 // On Solaris and illumos we can see EINVAL if the socket has
74 // already been accepted and closed by the server. Treat this
75 // as a successful connection--writes to the socket will see
76 // EOF. For details and a test case in C see
77 // https://golang.org/issue/6828.
78 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
83 return nil, os.NewSyscallError("connect", err)
85 if err := fd.pfd.Init(fd.net, true); err != nil {
88 if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
89 fd.pfd.SetWriteDeadline(deadline)
90 defer fd.pfd.SetWriteDeadline(noDeadline)
93 // Start the "interrupter" goroutine, if this context might be canceled.
95 // The interrupter goroutine waits for the context to be done and
96 // interrupts the dial (by altering the fd's write deadline, which
97 // wakes up waitWrite).
100 // Wait for the interrupter goroutine to exit before returning
102 done := make(chan struct{})
103 interruptRes := make(chan error)
106 if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
107 // The interrupter goroutine called SetWriteDeadline,
108 // but the connect code below had returned from
109 // waitWrite already and did a successful connect (ret
110 // == nil). Because we've now poisoned the connection
111 // by making it unwritable, don't return a successful
112 // dial. This was issue 16523.
114 fd.Close() // prevent a leak
120 // Force the runtime's poller to immediately give up
121 // waiting for writability, unblocking waitWrite
123 fd.pfd.SetWriteDeadline(aLongTimeAgo)
124 testHookCanceledDial()
125 interruptRes <- ctx.Err()
133 // Performing multiple connect system calls on a
134 // non-blocking socket under Unix variants does not
135 // necessarily result in earlier errors being
136 // returned. Instead, once runtime-integrated network
137 // poller tells us that the socket is ready, get the
138 // SO_ERROR socket option to see if the connection
139 // succeeded or failed. See issue 7474 for further
141 if err := fd.pfd.WaitWrite(); err != nil {
144 return nil, mapErr(ctx.Err())
149 nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
151 return nil, os.NewSyscallError("getsockopt", err)
153 switch err := syscall.Errno(nerr); err {
154 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
155 case syscall.EISCONN:
157 case syscall.Errno(0):
158 // The runtime poller can wake us up spuriously;
159 // see issues 14548 and 19289. Check that we are
160 // really connected; if not, wait again.
161 if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
165 return nil, os.NewSyscallError("connect", err)
167 runtime.KeepAlive(fd)
171 func (fd *netFD) accept() (netfd *netFD, err error) {
172 d, rsa, errcall, err := fd.pfd.Accept()
175 err = wrapSyscallError(errcall, err)
180 if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
184 if err = netfd.init(); err != nil {
188 lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
189 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
193 // Defined in os package.
194 func newUnixFile(fd int, name string) *os.File
196 func (fd *netFD) dup() (f *os.File, err error) {
197 ns, call, err := fd.pfd.Dup()
200 err = os.NewSyscallError(call, err)
205 return newUnixFile(ns, fd.name()), nil