microsoft / go-winio

Win32 IO-related utilities for Go
MIT License
939 stars 181 forks source link

pipe.Accept() hangs on Windows 2008 R2 and Windows 7 #313

Open Yraid opened 5 months ago

Yraid commented 5 months ago

How do we replicate the issue?

Finding

I used dlv to look around and it turned out that connectNamedPipe can't get ERROR_IO_CONNECTED on older platforms. It got ERROR_IO_PENDING. Thus the following asyncIO call is pending forever (so does connectPipe and Accept). On the other hand, newer platforms can get ERROR_IO_CONNECTED.

I'm not sure if the connectNamedPipe call is implemented differently on platforms like Windows 2008 R2 and Windows 10. I refer to changes: #125 and #80 and I can fix this issue by adding the following code snippets in ListenPipe after the makeServerPipeHandle call:

h2, err := fs.CreateFile(path, 0, 0, nil, syscall.OPEN_EXISTING, fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS, 0)
if err != nil && err != windows.ERROR_PIPE_BUSY {
    syscall.Close(syscall.Handle(h))
    return nil, err
}
if err == nil {
        syscall.Close(syscall.Handle(h2))
}

The reason for ignoring windows.ERROR_PIPE_BUSY is that we got this error when a real client is connecting before the dummy client, but we don't care about this error as the dummy client will be closed soon. The idea is to call fs.CreateFile to keep the pipe server "awake".

Questions

darwin-cometbackup commented 4 months ago

I've reproduced this behaviour (go-winio v0.5.2 built with go 1.20.10) and applied the fix and it resolved my issue. It was working on go-winio v0.4.12.

Though I'm not an expert on this area so I cannot comment on the fix itself.