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