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 readSyscallName
= "wsarecv"
18 readFromSyscallName
= "wsarecvfrom"
19 readMsgSyscallName
= "wsarecvmsg"
20 writeSyscallName
= "wsasend"
21 writeToSyscallName
= "wsasendto"
22 writeMsgSyscallName
= "wsasendmsg"
25 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
26 // for the given network type.
27 func canUseConnectEx(net
string) bool {
29 case "tcp", "tcp4", "tcp6":
32 // ConnectEx windows API does not support connectionless sockets.
36 func newFD(sysfd syscall
.Handle
, family
, sotype
int, net
string) (*netFD
, error
) {
40 IsStream
: sotype
== syscall
.SOCK_STREAM
,
41 ZeroReadIsEOF
: sotype
!= syscall
.SOCK_DGRAM
&& sotype
!= syscall
.SOCK_RAW
,
50 func (fd
*netFD
) init() error
{
51 errcall
, err
:= fd
.pfd
.Init(fd
.net
, true)
53 err
= wrapSyscallError(errcall
, err
)
58 // Always returns nil for connected peer address result.
59 func (fd
*netFD
) connect(ctx context
.Context
, la
, ra syscall
.Sockaddr
) (syscall
.Sockaddr
, error
) {
60 // Do not need to call fd.writeLock here,
61 // because fd is not yet accessible to user,
62 // so no concurrent operations are possible.
63 if err
:= fd
.init(); err
!= nil {
66 if deadline
, ok
:= ctx
.Deadline(); ok
&& !deadline
.IsZero() {
67 fd
.pfd
.SetWriteDeadline(deadline
)
68 defer fd
.pfd
.SetWriteDeadline(noDeadline
)
70 if !canUseConnectEx(fd
.net
) {
71 err
:= connectFunc(fd
.pfd
.Sysfd
, ra
)
72 return nil, os
.NewSyscallError("connect", err
)
74 // ConnectEx windows API requires an unconnected, previously bound socket.
77 case *syscall
.SockaddrInet4
:
78 la
= &syscall
.SockaddrInet4
{}
79 case *syscall
.SockaddrInet6
:
80 la
= &syscall
.SockaddrInet6
{}
82 panic("unexpected type in connect")
84 if err
:= syscall
.Bind(fd
.pfd
.Sysfd
, la
); err
!= nil {
85 return nil, os
.NewSyscallError("bind", err
)
89 // Wait for the goroutine converting context.Done into a write timeout
90 // to exist, otherwise our caller might cancel the context and
91 // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
92 done
:= make(chan bool) // must be unbuffered
93 defer func() { done
<- true }()
97 // Force the runtime's poller to immediately give
98 // up waiting for writability.
99 fd
.pfd
.SetWriteDeadline(aLongTimeAgo
)
105 // Call ConnectEx API.
106 if err
:= fd
.pfd
.ConnectEx(ra
); err
!= nil {
109 return nil, mapErr(ctx
.Err())
111 if _
, ok
:= err
.(syscall
.Errno
); ok
{
112 err
= os
.NewSyscallError("connectex", err
)
117 // Refresh socket properties.
118 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
))))
121 func (c
*conn
) writeBuffers(v
*Buffers
) (int64, error
) {
123 return 0, syscall
.EINVAL
125 n
, err
:= c
.fd
.writeBuffers(v
)
127 return n
, &OpError
{Op
: "wsasend", Net
: c
.fd
.net
, Source
: c
.fd
.laddr
, Addr
: c
.fd
.raddr
, Err
: err
}
132 func (fd
*netFD
) writeBuffers(buf
*Buffers
) (int64, error
) {
133 n
, err
:= fd
.pfd
.Writev((*[][]byte)(buf
))
134 runtime
.KeepAlive(fd
)
135 return n
, wrapSyscallError("wsasend", err
)
138 func (fd
*netFD
) accept() (*netFD
, error
) {
139 s
, rawsa
, rsan
, errcall
, err
:= fd
.pfd
.Accept(func() (syscall
.Handle
, error
) {
140 return sysSocket(fd
.family
, fd
.sotype
, 0)
145 err
= wrapSyscallError(errcall
, err
)
150 // Associate our new socket with IOCP.
151 netfd
, err
:= newFD(s
, fd
.family
, fd
.sotype
, fd
.net
)
156 if err
:= netfd
.init(); err
!= nil {
161 // Get local and peer addr out of AcceptEx buffer.
162 var lrsa
, rrsa
*syscall
.RawSockaddrAny
164 syscall
.GetAcceptExSockaddrs((*byte)(unsafe
.Pointer(&rawsa
[0])),
165 0, rsan
, rsan
, &lrsa
, &llen
, &rrsa
, &rlen
)
166 lsa
, _
:= lrsa
.Sockaddr()
167 rsa
, _
:= rrsa
.Sockaddr()
169 netfd
.setAddr(netfd
.addrFunc()(lsa
), netfd
.addrFunc()(rsa
))
173 // Unimplemented functions.
175 func (fd
*netFD
) dup() (*os
.File
, error
) {
176 // TODO: Implement this
177 return nil, syscall
.EWINDOWS