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.
17 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
18 // for the given network type.
19 func canUseConnectEx(net
string) bool {
21 case "tcp", "tcp4", "tcp6":
24 // ConnectEx windows API does not support connectionless sockets.
28 // Network file descriptor.
32 // immutable until Close
35 isConnected
bool // handshake completed or use of association with peer
41 func newFD(sysfd syscall
.Handle
, family
, sotype
int, net
string) (*netFD
, error
) {
45 IsStream
: sotype
== syscall
.SOCK_STREAM
,
46 ZeroReadIsEOF
: sotype
!= syscall
.SOCK_DGRAM
&& sotype
!= syscall
.SOCK_RAW
,
55 func (fd
*netFD
) init() error
{
56 errcall
, err
:= fd
.pfd
.Init(fd
.net
, true)
58 err
= wrapSyscallError(errcall
, err
)
63 func (fd
*netFD
) setAddr(laddr
, raddr Addr
) {
66 runtime
.SetFinalizer(fd
, (*netFD
).Close
)
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 {
77 if deadline
, ok
:= ctx
.Deadline(); ok
&& !deadline
.IsZero() {
78 fd
.pfd
.SetWriteDeadline(deadline
)
79 defer fd
.pfd
.SetWriteDeadline(noDeadline
)
81 if !canUseConnectEx(fd
.net
) {
82 err
:= connectFunc(fd
.pfd
.Sysfd
, ra
)
83 return nil, os
.NewSyscallError("connect", err
)
85 // ConnectEx windows API requires an unconnected, previously bound socket.
88 case *syscall
.SockaddrInet4
:
89 la
= &syscall
.SockaddrInet4
{}
90 case *syscall
.SockaddrInet6
:
91 la
= &syscall
.SockaddrInet6
{}
93 panic("unexpected type in connect")
95 if err
:= syscall
.Bind(fd
.pfd
.Sysfd
, la
); err
!= nil {
96 return nil, os
.NewSyscallError("bind", err
)
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 }()
108 // Force the runtime's poller to immediately give
109 // up waiting for writability.
110 fd
.pfd
.SetWriteDeadline(aLongTimeAgo
)
116 // Call ConnectEx API.
117 if err
:= fd
.pfd
.ConnectEx(ra
); err
!= nil {
120 return nil, mapErr(ctx
.Err())
122 if _
, ok
:= err
.(syscall
.Errno
); ok
{
123 err
= os
.NewSyscallError("connectex", err
)
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
))))
132 func (fd
*netFD
) Close() error
{
133 runtime
.SetFinalizer(fd
, nil)
134 return fd
.pfd
.Close()
137 func (fd
*netFD
) shutdown(how
int) error
{
138 err
:= fd
.pfd
.Shutdown(how
)
139 runtime
.KeepAlive(fd
)
143 func (fd
*netFD
) closeRead() error
{
144 return fd
.shutdown(syscall
.SHUT_RD
)
147 func (fd
*netFD
) closeWrite() error
{
148 return fd
.shutdown(syscall
.SHUT_WR
)
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
)
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
)
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
)
169 func (c
*conn
) writeBuffers(v
*Buffers
) (int64, error
) {
171 return 0, syscall
.EINVAL
173 n
, err
:= c
.fd
.writeBuffers(v
)
175 return n
, &OpError
{Op
: "wsasend", Net
: c
.fd
.net
, Source
: c
.fd
.laddr
, Addr
: c
.fd
.raddr
, Err
: err
}
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
)
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
)
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)
199 err
= wrapSyscallError(errcall
, err
)
204 // Associate our new socket with IOCP.
205 netfd
, err
:= newFD(s
, fd
.family
, fd
.sotype
, fd
.net
)
210 if err
:= netfd
.init(); err
!= nil {
215 // Get local and peer addr out of AcceptEx buffer.
216 var lrsa
, rrsa
*syscall
.RawSockaddrAny
218 syscall
.GetAcceptExSockaddrs((*byte)(unsafe
.Pointer(&rawsa
[0])),
219 0, rsan
, rsan
, &lrsa
, &llen
, &rrsa
, &rlen
)
220 lsa
, _
:= lrsa
.Sockaddr()
221 rsa
, _
:= rrsa
.Sockaddr()
223 netfd
.setAddr(netfd
.addrFunc()(lsa
), netfd
.addrFunc()(rsa
))
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
)
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
)
239 // Unimplemented functions.
241 func (fd
*netFD
) dup() (*os
.File
, error
) {
242 // TODO: Implement this
243 return nil, syscall
.EWINDOWS
246 func (fd
*netFD
) SetDeadline(t time
.Time
) error
{
247 return fd
.pfd
.SetDeadline(t
)
250 func (fd
*netFD
) SetReadDeadline(t time
.Time
) error
{
251 return fd
.pfd
.SetReadDeadline(t
)
254 func (fd
*netFD
) SetWriteDeadline(t time
.Time
) error
{
255 return fd
.pfd
.SetWriteDeadline(t
)