Skip to content

Commit 3bcdfc9

Browse files
committed
net, syscall, internal/syscall/windows: implement FileConn, FilePacketConn, FileListener
DO NOT REVIEW Fixes golang#9503. Fixes golang#10350. Change-Id: If0851cb3340281cc1ea523cd0ddf48fc7f87c775
1 parent 665b9b3 commit 3bcdfc9

File tree

7 files changed

+714
-9
lines changed

7 files changed

+714
-9
lines changed

src/internal/syscall/windows/syscall_windows.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ type IpAdapterAddresses struct {
101101
/* more fields might be present here. */
102102
}
103103

104+
type WSANetworkEvents struct {
105+
NetworkEvents int32
106+
ErrorCode [10]int32
107+
}
108+
104109
const (
105110
IfOperStatusUp = 1
106111
IfOperStatusDown = 2
@@ -292,3 +297,15 @@ const (
292297
func LoadGetFinalPathNameByHandle() error {
293298
return procGetFinalPathNameByHandleW.Find()
294299
}
300+
301+
const (
302+
SO_TYPE = 0x1008
303+
)
304+
305+
const (
306+
HANDLE_FLAG_INHERIT = 0x01
307+
HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x02
308+
)
309+
310+
//sys WSAEnumNetworkEvents(handle syscall.Handle, event syscall.Handle, events *WSANetworkEvents) (err error) [failretval==socket_error] = ws2_32.WSAEnumNetworkEvents
311+
//sys GetHandleInformation(handle syscall.Handle, flags *uint32) (err error) = GetHandleInformation

src/internal/syscall/windows/zsyscall_windows.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ var (
6666
procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
6767
procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
6868
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
69+
70+
procWSAEnumNetworkEvents = modws2_32.NewProc("WSAEnumNetworkEvents")
71+
procGetHandleInformation = modkernel32.NewProc("GetHandleInformation")
6972
)
7073

7174
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
@@ -321,3 +324,27 @@ func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COU
321324
}
322325
return
323326
}
327+
328+
func WSAEnumNetworkEvents(handle syscall.Handle, event syscall.Handle, events *WSANetworkEvents) (err error) {
329+
r1, _, e1 := syscall.Syscall(procWSAEnumNetworkEvents.Addr(), 3, uintptr(handle), uintptr(event), uintptr(unsafe.Pointer(events)))
330+
if r1 == socket_error {
331+
if e1 != 0 {
332+
err = error(e1)
333+
} else {
334+
err = syscall.EINVAL
335+
}
336+
}
337+
return
338+
}
339+
340+
func GetHandleInformation(handle syscall.Handle, flags *uint32) (err error) {
341+
r1, _, e1 := syscall.Syscall(procGetHandleInformation.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(flags)), 0)
342+
if r1 == 0 {
343+
if e1 != 0 {
344+
err = error(e1)
345+
} else {
346+
err = syscall.EINVAL
347+
}
348+
}
349+
return
350+
}

src/net/fd_windows.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type netFD struct {
3535
net string
3636
laddr Addr
3737
raddr Addr
38+
isFile bool
3839
}
3940

4041
func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
@@ -206,6 +207,7 @@ func (fd *netFD) accept() (*netFD, error) {
206207
poll.CloseFunc(s)
207208
return nil, err
208209
}
210+
netfd.isFile = fd.isFile
209211
if err := netfd.init(); err != nil {
210212
fd.Close()
211213
return nil, err
@@ -238,6 +240,24 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
238240
// Unimplemented functions.
239241

240242
func (fd *netFD) dup() (*os.File, error) {
241-
// TODO: Implement this
242-
return nil, syscall.EWINDOWS
243+
var s syscall.Handle
244+
p, _ := syscall.GetCurrentProcess()
245+
err := syscall.DuplicateHandle(p, syscall.Handle(fd.pfd.Sysfd), p, &s, 0, true, syscall.DUPLICATE_SAME_ACCESS)
246+
if err != nil {
247+
return nil, os.NewSyscallError("duplicatehandle", err)
248+
}
249+
return os.NewFile(uintptr(s), fd.name()), nil
250+
}
251+
252+
// Unimplemented functions.
253+
254+
func (fd *netFD) name() string {
255+
var ls, rs string
256+
if fd.laddr != nil {
257+
ls = fd.laddr.String()
258+
}
259+
if fd.raddr != nil {
260+
rs = fd.raddr.String()
261+
}
262+
return fd.net + ":" + ls + "->" + rs
243263
}

src/net/file_windows.go

Lines changed: 111 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,126 @@
55
package net
66

77
import (
8+
"internal/poll"
9+
"internal/syscall/windows"
810
"os"
911
"syscall"
1012
)
1113

14+
func dupCloseOnExec(s int) (syscall.Handle, error) {
15+
var ns syscall.Handle
16+
p, _ := syscall.GetCurrentProcess()
17+
err := syscall.DuplicateHandle(p, syscall.Handle(s), p, &ns, 0, false, syscall.DUPLICATE_SAME_ACCESS)
18+
if err != nil {
19+
return syscall.InvalidHandle, os.NewSyscallError("duplicatehandle", err)
20+
}
21+
return ns, nil
22+
}
23+
24+
func newFileFD(f *os.File) (*netFD, error) {
25+
var flags uint32
26+
27+
var err error
28+
s := syscall.Handle(f.Fd())
29+
if err := windows.GetHandleInformation(s, &flags); err != nil {
30+
return nil, err
31+
}
32+
33+
s, err = dupCloseOnExec(int(f.Fd()))
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
if err = syscall.SetNonblock(s, true); err != nil {
39+
poll.CloseFunc(s)
40+
return nil, err
41+
}
42+
family := syscall.AF_UNSPEC
43+
sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, windows.SO_TYPE)
44+
if err != nil {
45+
poll.CloseFunc(s)
46+
return nil, os.NewSyscallError("getsockopt", err)
47+
}
48+
lsa, _ := syscall.Getsockname(s)
49+
rsa, _ := syscall.Getpeername(s)
50+
switch lsa.(type) {
51+
case *syscall.SockaddrInet4:
52+
family = syscall.AF_INET
53+
case *syscall.SockaddrInet6:
54+
family = syscall.AF_INET6
55+
case *syscall.SockaddrUnix:
56+
poll.CloseFunc(s)
57+
return nil, syscall.EWINDOWS
58+
default:
59+
poll.CloseFunc(s)
60+
return nil, syscall.EPROTONOSUPPORT
61+
}
62+
fd, err := newFD(s, family, sotype, "")
63+
if err != nil {
64+
poll.CloseFunc(s)
65+
return nil, err
66+
}
67+
laddr := fd.addrFunc()(lsa)
68+
raddr := fd.addrFunc()(rsa)
69+
fd.net = laddr.Network()
70+
if _, err := fd.pfd.Init("tcp", fd.isFile); err != nil {
71+
fd.Close()
72+
return nil, err
73+
}
74+
fd.setAddr(laddr, raddr)
75+
return fd, nil
76+
}
77+
1278
func fileConn(f *os.File) (Conn, error) {
13-
// TODO: Implement this
14-
return nil, syscall.EWINDOWS
79+
fd, err := newFileFD(f)
80+
if err != nil {
81+
return nil, err
82+
}
83+
switch fd.laddr.(type) {
84+
case *TCPAddr:
85+
return newTCPConn(fd), nil
86+
case *UDPAddr:
87+
return newUDPConn(fd), nil
88+
case *IPAddr:
89+
return newIPConn(fd), nil
90+
case *UnixAddr:
91+
fd.Close()
92+
return nil, syscall.EWINDOWS
93+
}
94+
fd.Close()
95+
return nil, syscall.EINVAL
1596
}
1697

1798
func fileListener(f *os.File) (Listener, error) {
18-
// TODO: Implement this
19-
return nil, syscall.EWINDOWS
99+
fd, err := newFileFD(f)
100+
if err != nil {
101+
return nil, err
102+
}
103+
switch fd.laddr.(type) {
104+
case *TCPAddr:
105+
return &TCPListener{fd}, nil
106+
case *UnixAddr:
107+
fd.Close()
108+
return nil, syscall.EWINDOWS
109+
}
110+
fd.Close()
111+
return nil, syscall.EINVAL
20112
}
21113

22114
func filePacketConn(f *os.File) (PacketConn, error) {
23-
// TODO: Implement this
24-
return nil, syscall.EWINDOWS
115+
fd, err := newFileFD(f)
116+
if err != nil {
117+
return nil, err
118+
}
119+
switch fd.laddr.(type) {
120+
case *UDPAddr:
121+
return newUDPConn(fd), nil
122+
case *IPAddr:
123+
return newIPConn(fd), nil
124+
case *UnixAddr:
125+
fd.Close()
126+
return nil, syscall.EWINDOWS
127+
}
128+
fd.Close()
129+
return nil, syscall.EINVAL
25130
}

0 commit comments

Comments
 (0)