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.
16 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
17 // for the given network type.
18 func canUseConnectEx(net
string) bool {
20 case "tcp", "tcp4", "tcp6":
23 // ConnectEx windows API does not support connectionless sockets.
27 // Network file descriptor.
31 // immutable until Close
40 func newFD(sysfd syscall
.Handle
, family
, sotype
int, net
string) (*netFD
, error
) {
44 IsStream
: sotype
== syscall
.SOCK_STREAM
,
45 ZeroReadIsEOF
: sotype
!= syscall
.SOCK_DGRAM
&& sotype
!= syscall
.SOCK_RAW
,
54 func (fd
*netFD
) init() error
{
55 errcall
, err
:= fd
.pfd
.Init(fd
.net
)
57 err
= wrapSyscallError(errcall
, err
)
62 func (fd
*netFD
) setAddr(laddr
, raddr Addr
) {
65 runtime
.SetFinalizer(fd
, (*netFD
).Close
)
68 // Always returns nil for connected peer address result.
69 func (fd
*netFD
) connect(ctx context
.Context
, la
, ra syscall
.Sockaddr
) (syscall
.Sockaddr
, 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 if err
:= fd
.init(); err
!= nil {
76 if deadline
, ok
:= ctx
.Deadline(); ok
&& !deadline
.IsZero() {
77 fd
.pfd
.SetWriteDeadline(deadline
)
78 defer fd
.pfd
.SetWriteDeadline(noDeadline
)
80 if !canUseConnectEx(fd
.net
) {
81 err
:= connectFunc(fd
.pfd
.Sysfd
, ra
)
82 return nil, os
.NewSyscallError("connect", err
)
84 // ConnectEx windows API requires an unconnected, previously bound socket.
87 case *syscall
.SockaddrInet4
:
88 la
= &syscall
.SockaddrInet4
{}
89 case *syscall
.SockaddrInet6
:
90 la
= &syscall
.SockaddrInet6
{}
92 panic("unexpected type in connect")
94 if err
:= syscall
.Bind(fd
.pfd
.Sysfd
, la
); err
!= nil {
95 return nil, os
.NewSyscallError("bind", err
)
99 // Wait for the goroutine converting context.Done into a write timeout
100 // to exist, otherwise our caller might cancel the context and
101 // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
102 done
:= make(chan bool) // must be unbuffered
103 defer func() { done
<- true }()
107 // Force the runtime's poller to immediately give
108 // up waiting for writability.
109 fd
.pfd
.SetWriteDeadline(aLongTimeAgo
)
115 // Call ConnectEx API.
116 if err
:= fd
.pfd
.ConnectEx(ra
); err
!= nil {
119 return nil, mapErr(ctx
.Err())
121 if _
, ok
:= err
.(syscall
.Errno
); ok
{
122 err
= os
.NewSyscallError("connectex", err
)
127 // Refresh socket properties.
128 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
))))
131 func (fd
*netFD
) Close() error
{
132 runtime
.SetFinalizer(fd
, nil)
133 return fd
.pfd
.Close()
136 func (fd
*netFD
) shutdown(how
int) error
{
137 err
:= fd
.pfd
.Shutdown(how
)
138 runtime
.KeepAlive(fd
)
142 func (fd
*netFD
) closeRead() error
{
143 return fd
.shutdown(syscall
.SHUT_RD
)
146 func (fd
*netFD
) closeWrite() error
{
147 return fd
.shutdown(syscall
.SHUT_WR
)
150 func (fd
*netFD
) Read(buf
[]byte) (int, error
) {
151 n
, err
:= fd
.pfd
.Read(buf
)
152 runtime
.KeepAlive(fd
)
153 return n
, wrapSyscallError("wsarecv", err
)
156 func (fd
*netFD
) readFrom(buf
[]byte) (int, syscall
.Sockaddr
, error
) {
157 n
, sa
, err
:= fd
.pfd
.ReadFrom(buf
)
158 runtime
.KeepAlive(fd
)
159 return n
, sa
, wrapSyscallError("wsarecvfrom", err
)
162 func (fd
*netFD
) Write(buf
[]byte) (int, error
) {
163 n
, err
:= fd
.pfd
.Write(buf
)
164 runtime
.KeepAlive(fd
)
165 return n
, wrapSyscallError("wsasend", err
)
168 func (c
*conn
) writeBuffers(v
*Buffers
) (int64, error
) {
170 return 0, syscall
.EINVAL
172 n
, err
:= c
.fd
.writeBuffers(v
)
174 return n
, &OpError
{Op
: "wsasend", Net
: c
.fd
.net
, Source
: c
.fd
.laddr
, Addr
: c
.fd
.raddr
, Err
: err
}
179 func (fd
*netFD
) writeBuffers(buf
*Buffers
) (int64, error
) {
180 n
, err
:= fd
.pfd
.Writev((*[][]byte)(buf
))
181 runtime
.KeepAlive(fd
)
182 return n
, wrapSyscallError("wsasend", err
)
185 func (fd
*netFD
) writeTo(buf
[]byte, sa syscall
.Sockaddr
) (int, error
) {
186 n
, err
:= fd
.pfd
.WriteTo(buf
, sa
)
187 runtime
.KeepAlive(fd
)
188 return n
, wrapSyscallError("wsasendto", err
)
191 func (fd
*netFD
) accept() (*netFD
, error
) {
192 s
, rawsa
, rsan
, errcall
, err
:= fd
.pfd
.Accept(func() (syscall
.Handle
, error
) {
193 return sysSocket(fd
.family
, fd
.sotype
, 0)
198 err
= wrapSyscallError(errcall
, err
)
203 // Associate our new socket with IOCP.
204 netfd
, err
:= newFD(s
, fd
.family
, fd
.sotype
, fd
.net
)
209 if err
:= netfd
.init(); err
!= nil {
214 // Get local and peer addr out of AcceptEx buffer.
215 var lrsa
, rrsa
*syscall
.RawSockaddrAny
217 syscall
.GetAcceptExSockaddrs((*byte)(unsafe
.Pointer(&rawsa
[0])),
218 0, rsan
, rsan
, &lrsa
, &llen
, &rrsa
, &rlen
)
219 lsa
, _
:= lrsa
.Sockaddr()
220 rsa
, _
:= rrsa
.Sockaddr()
222 netfd
.setAddr(netfd
.addrFunc()(lsa
), netfd
.addrFunc()(rsa
))
226 // Unimplemented functions.
228 func (fd
*netFD
) dup() (*os
.File
, error
) {
229 // TODO: Implement this
230 return nil, syscall
.EWINDOWS
233 func (fd
*netFD
) readMsg(p
[]byte, oob
[]byte) (n
, oobn
, flags
int, sa syscall
.Sockaddr
, err error
) {
234 return 0, 0, 0, nil, syscall
.EWINDOWS
237 func (fd
*netFD
) writeMsg(p
[]byte, oob
[]byte, sa syscall
.Sockaddr
) (n
int, oobn
int, err error
) {
238 return 0, 0, syscall
.EWINDOWS