Source file
src/internal/poll/fd_windows_test.go
1
2
3
4
5 package poll_test
6
7 import (
8 "errors"
9 "fmt"
10 "internal/poll"
11 "internal/syscall/windows"
12 "os"
13 "sync"
14 "syscall"
15 "testing"
16 "unsafe"
17 )
18
19 type loggedFD struct {
20 Net string
21 FD *poll.FD
22 Err error
23 }
24
25 var (
26 logMu sync.Mutex
27 loggedFDs map[syscall.Handle]*loggedFD
28 )
29
30 func logFD(net string, fd *poll.FD, err error) {
31 logMu.Lock()
32 defer logMu.Unlock()
33
34 loggedFDs[fd.Sysfd] = &loggedFD{
35 Net: net,
36 FD: fd,
37 Err: err,
38 }
39 }
40
41 func init() {
42 loggedFDs = make(map[syscall.Handle]*loggedFD)
43 *poll.LogInitFD = logFD
44 }
45
46 func findLoggedFD(h syscall.Handle) (lfd *loggedFD, found bool) {
47 logMu.Lock()
48 defer logMu.Unlock()
49
50 lfd, found = loggedFDs[h]
51 return lfd, found
52 }
53
54
55
56 func checkFileIsNotPartOfNetpoll(f *os.File) error {
57 lfd, found := findLoggedFD(syscall.Handle(f.Fd()))
58 if !found {
59 return fmt.Errorf("%v fd=%v: is not found in the log", f.Name(), f.Fd())
60 }
61 if lfd.FD.IsPartOfNetpoll() {
62 return fmt.Errorf("%v fd=%v: is part of netpoll, but should not be (logged: net=%v err=%v)", f.Name(), f.Fd(), lfd.Net, lfd.Err)
63 }
64 return nil
65 }
66
67 func TestFileFdsAreInitialised(t *testing.T) {
68 exe, err := os.Executable()
69 if err != nil {
70 t.Fatal(err)
71 }
72 f, err := os.Open(exe)
73 if err != nil {
74 t.Fatal(err)
75 }
76 defer f.Close()
77
78 err = checkFileIsNotPartOfNetpoll(f)
79 if err != nil {
80 t.Fatal(err)
81 }
82 }
83
84 func TestSerialFdsAreInitialised(t *testing.T) {
85 for _, name := range []string{"COM1", "COM2", "COM3", "COM4"} {
86 t.Run(name, func(t *testing.T) {
87 h, err := syscall.CreateFile(syscall.StringToUTF16Ptr(name),
88 syscall.GENERIC_READ|syscall.GENERIC_WRITE,
89 0,
90 nil,
91 syscall.OPEN_EXISTING,
92 syscall.FILE_ATTRIBUTE_NORMAL|syscall.FILE_FLAG_OVERLAPPED,
93 0)
94 if err != nil {
95 if errno, ok := err.(syscall.Errno); ok {
96 switch errno {
97 case syscall.ERROR_FILE_NOT_FOUND,
98 syscall.ERROR_ACCESS_DENIED:
99 t.Log("Skipping: ", err)
100 return
101 }
102 }
103 t.Fatal(err)
104 }
105 f := os.NewFile(uintptr(h), name)
106 defer f.Close()
107
108 err = checkFileIsNotPartOfNetpoll(f)
109 if err != nil {
110 t.Fatal(err)
111 }
112 })
113 }
114 }
115
116 func TestWSASocketConflict(t *testing.T) {
117 s, err := windows.WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, windows.WSA_FLAG_OVERLAPPED)
118 if err != nil {
119 t.Fatal(err)
120 }
121 fd := poll.FD{Sysfd: s, IsStream: true, ZeroReadIsEOF: true}
122 _, err = fd.Init("tcp", true)
123 if err != nil {
124 syscall.CloseHandle(s)
125 t.Fatal(err)
126 }
127 defer fd.Close()
128
129 const SIO_TCP_INFO = syscall.IOC_INOUT | syscall.IOC_VENDOR | 39
130 inbuf := uint32(0)
131 var outbuf _TCP_INFO_v0
132 cbbr := uint32(0)
133
134 var ovs []syscall.Overlapped = make([]syscall.Overlapped, 2)
135
136
137
138 ovs[1].Internal -= 1
139
140
141
142 ovs[0].HEvent, _ = windows.CreateEvent(nil, 0, 0, nil)
143 if ovs[0].HEvent == 0 {
144 t.Fatalf("could not create the event!")
145 }
146
147
148
149
150 ovs[0].HEvent |= 0x1
151
152 if err = fd.WSAIoctl(
153 SIO_TCP_INFO,
154 (*byte)(unsafe.Pointer(&inbuf)),
155 uint32(unsafe.Sizeof(inbuf)),
156 (*byte)(unsafe.Pointer(&outbuf)),
157 uint32(unsafe.Sizeof(outbuf)),
158 &cbbr,
159 &ovs[0],
160 0,
161 ); err != nil && !errors.Is(err, syscall.ERROR_IO_PENDING) {
162 t.Fatalf("could not perform the WSAIoctl: %v", err)
163 }
164
165 if err != nil && errors.Is(err, syscall.ERROR_IO_PENDING) {
166
167
168 if res, err := syscall.WaitForSingleObject(ovs[0].HEvent, syscall.INFINITE); res != 0 {
169 t.Fatalf("waiting for the completion of the overlapped IO failed: %v", err)
170 }
171 }
172
173 if err = syscall.CloseHandle(ovs[0].HEvent); err != nil {
174 t.Fatalf("could not close the event handle: %v", err)
175 }
176 }
177
178 type _TCP_INFO_v0 struct {
179 State uint32
180 Mss uint32
181 ConnectionTimeMs uint64
182 TimestampsEnabled bool
183 RttUs uint32
184 MinRttUs uint32
185 BytesInFlight uint32
186 Cwnd uint32
187 SndWnd uint32
188 RcvWnd uint32
189 RcvBuf uint32
190 BytesOut uint64
191 BytesIn uint64
192 BytesReordered uint32
193 BytesRetrans uint32
194 FastRetrans uint32
195 DupAcksIn uint32
196 TimeoutEpisodes uint32
197 SynRetrans uint8
198 }
199
View as plain text