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