runtime: correct facilities names in s390 CPU support
[gcc.git] / libgo / go / net / fd_windows.go
1 // Copyright 2010 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 package net
6
7 import (
8 "context"
9 "internal/poll"
10 "os"
11 "runtime"
12 "syscall"
13 "time"
14 "unsafe"
15 )
16
17 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
18 // for the given network type.
19 func canUseConnectEx(net string) bool {
20 switch net {
21 case "tcp", "tcp4", "tcp6":
22 return true
23 }
24 // ConnectEx windows API does not support connectionless sockets.
25 return false
26 }
27
28 // Network file descriptor.
29 type netFD struct {
30 pfd poll.FD
31
32 // immutable until Close
33 family int
34 sotype int
35 isConnected bool // handshake completed or use of association with peer
36 net string
37 laddr Addr
38 raddr Addr
39 }
40
41 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
42 ret := &netFD{
43 pfd: poll.FD{
44 Sysfd: sysfd,
45 IsStream: sotype == syscall.SOCK_STREAM,
46 ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
47 },
48 family: family,
49 sotype: sotype,
50 net: net,
51 }
52 return ret, nil
53 }
54
55 func (fd *netFD) init() error {
56 errcall, err := fd.pfd.Init(fd.net, true)
57 if errcall != "" {
58 err = wrapSyscallError(errcall, err)
59 }
60 return err
61 }
62
63 func (fd *netFD) setAddr(laddr, raddr Addr) {
64 fd.laddr = laddr
65 fd.raddr = raddr
66 runtime.SetFinalizer(fd, (*netFD).Close)
67 }
68
69 // Always returns nil for connected peer address result.
70 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) {
71 // Do not need to call fd.writeLock here,
72 // because fd is not yet accessible to user,
73 // so no concurrent operations are possible.
74 if err := fd.init(); err != nil {
75 return nil, err
76 }
77 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
78 fd.pfd.SetWriteDeadline(deadline)
79 defer fd.pfd.SetWriteDeadline(noDeadline)
80 }
81 if !canUseConnectEx(fd.net) {
82 err := connectFunc(fd.pfd.Sysfd, ra)
83 return nil, os.NewSyscallError("connect", err)
84 }
85 // ConnectEx windows API requires an unconnected, previously bound socket.
86 if la == nil {
87 switch ra.(type) {
88 case *syscall.SockaddrInet4:
89 la = &syscall.SockaddrInet4{}
90 case *syscall.SockaddrInet6:
91 la = &syscall.SockaddrInet6{}
92 default:
93 panic("unexpected type in connect")
94 }
95 if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
96 return nil, os.NewSyscallError("bind", err)
97 }
98 }
99
100 // Wait for the goroutine converting context.Done into a write timeout
101 // to exist, otherwise our caller might cancel the context and
102 // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
103 done := make(chan bool) // must be unbuffered
104 defer func() { done <- true }()
105 go func() {
106 select {
107 case <-ctx.Done():
108 // Force the runtime's poller to immediately give
109 // up waiting for writability.
110 fd.pfd.SetWriteDeadline(aLongTimeAgo)
111 <-done
112 case <-done:
113 }
114 }()
115
116 // Call ConnectEx API.
117 if err := fd.pfd.ConnectEx(ra); err != nil {
118 select {
119 case <-ctx.Done():
120 return nil, mapErr(ctx.Err())
121 default:
122 if _, ok := err.(syscall.Errno); ok {
123 err = os.NewSyscallError("connectex", err)
124 }
125 return nil, err
126 }
127 }
128 // Refresh socket properties.
129 return nil, os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd))))
130 }
131
132 func (fd *netFD) Close() error {
133 runtime.SetFinalizer(fd, nil)
134 return fd.pfd.Close()
135 }
136
137 func (fd *netFD) shutdown(how int) error {
138 err := fd.pfd.Shutdown(how)
139 runtime.KeepAlive(fd)
140 return err
141 }
142
143 func (fd *netFD) closeRead() error {
144 return fd.shutdown(syscall.SHUT_RD)
145 }
146
147 func (fd *netFD) closeWrite() error {
148 return fd.shutdown(syscall.SHUT_WR)
149 }
150
151 func (fd *netFD) Read(buf []byte) (int, error) {
152 n, err := fd.pfd.Read(buf)
153 runtime.KeepAlive(fd)
154 return n, wrapSyscallError("wsarecv", err)
155 }
156
157 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
158 n, sa, err := fd.pfd.ReadFrom(buf)
159 runtime.KeepAlive(fd)
160 return n, sa, wrapSyscallError("wsarecvfrom", err)
161 }
162
163 func (fd *netFD) Write(buf []byte) (int, error) {
164 n, err := fd.pfd.Write(buf)
165 runtime.KeepAlive(fd)
166 return n, wrapSyscallError("wsasend", err)
167 }
168
169 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
170 if !c.ok() {
171 return 0, syscall.EINVAL
172 }
173 n, err := c.fd.writeBuffers(v)
174 if err != nil {
175 return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
176 }
177 return n, nil
178 }
179
180 func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
181 n, err := fd.pfd.Writev((*[][]byte)(buf))
182 runtime.KeepAlive(fd)
183 return n, wrapSyscallError("wsasend", err)
184 }
185
186 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
187 n, err := fd.pfd.WriteTo(buf, sa)
188 runtime.KeepAlive(fd)
189 return n, wrapSyscallError("wsasendto", err)
190 }
191
192 func (fd *netFD) accept() (*netFD, error) {
193 s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
194 return sysSocket(fd.family, fd.sotype, 0)
195 })
196
197 if err != nil {
198 if errcall != "" {
199 err = wrapSyscallError(errcall, err)
200 }
201 return nil, err
202 }
203
204 // Associate our new socket with IOCP.
205 netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
206 if err != nil {
207 poll.CloseFunc(s)
208 return nil, err
209 }
210 if err := netfd.init(); err != nil {
211 fd.Close()
212 return nil, err
213 }
214
215 // Get local and peer addr out of AcceptEx buffer.
216 var lrsa, rrsa *syscall.RawSockaddrAny
217 var llen, rlen int32
218 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
219 0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
220 lsa, _ := lrsa.Sockaddr()
221 rsa, _ := rrsa.Sockaddr()
222
223 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
224 return netfd, nil
225 }
226
227 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
228 n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
229 runtime.KeepAlive(fd)
230 return n, oobn, flags, sa, wrapSyscallError("wsarecvmsg", 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("wsasendmsg", err)
237 }
238
239 // Unimplemented functions.
240
241 func (fd *netFD) dup() (*os.File, error) {
242 // TODO: Implement this
243 return nil, syscall.EWINDOWS
244 }
245
246 func (fd *netFD) SetDeadline(t time.Time) error {
247 return fd.pfd.SetDeadline(t)
248 }
249
250 func (fd *netFD) SetReadDeadline(t time.Time) error {
251 return fd.pfd.SetReadDeadline(t)
252 }
253
254 func (fd *netFD) SetWriteDeadline(t time.Time) error {
255 return fd.pfd.SetWriteDeadline(t)
256 }