Skip to content

Commit

Permalink
Add support for flushing and disconnecting named pipes (#292)
Browse files Browse the repository at this point in the history
* Add support for disconnecting pipes

Signed-off-by: David Golub <[email protected]>

* Expose Flush

Signed-off-by: David Golub <[email protected]>

* Add test

Signed-off-by: David Golub <[email protected]>

* Fix lint errors

Signed-off-by: David Golub <[email protected]>

---------

Signed-off-by: David Golub <[email protected]>
  • Loading branch information
dgolub authored Jul 24, 2023
1 parent 19a9f65 commit b29bbd5
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
13 changes: 13 additions & 0 deletions pipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys disconnectNamedPipe(pipe syscall.Handle) (err error) = DisconnectNamedPipe
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
Expand All @@ -30,6 +31,12 @@ import (
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl

type PipeConn interface {
net.Conn
Disconnect() error
Flush() error
}

type ioStatusBlock struct {
Status, Information uintptr
}
Expand Down Expand Up @@ -80,6 +87,8 @@ type win32Pipe struct {
path string
}

var _ PipeConn = (*win32Pipe)(nil)

type win32MessageBytePipe struct {
win32Pipe
writeClosed bool
Expand All @@ -103,6 +112,10 @@ func (f *win32Pipe) SetDeadline(t time.Time) error {
return f.SetWriteDeadline(t)
}

func (f *win32Pipe) Disconnect() error {
return disconnectNamedPipe(f.win32File.handle)
}

// CloseWrite closes the write side of a message pipe in byte mode.
func (f *win32MessageBytePipe) CloseWrite() error {
if f.writeClosed {
Expand Down
60 changes: 60 additions & 0 deletions pipe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,66 @@ func TestTimeoutPendingWrite(t *testing.T) {
<-serverDone
}

func TestDisconnectPipe(t *testing.T) {
l, err := ListenPipe(testPipeName, nil)
if err != nil {
t.Fatal(err)
}
defer l.Close()

const testData = "foo"
serverDone := make(chan struct{})

go func() {
s, err := l.Accept()
if err != nil {
t.Error(err)
return
}
defer func() {
s.Close()
close(serverDone)
}()

if _, err := s.Write([]byte(testData)); err != nil {
t.Error(err)
return
}

if err := s.(PipeConn).Flush(); err != nil {
t.Error(err)
return
}

if err := s.(PipeConn).Disconnect(); err != nil {
t.Error(err)
return
}
}()

client, err := DialPipe(testPipeName, nil)
if err != nil {
t.Fatal(err)
}
defer client.Close()

buf := make([]byte, len(testData))
if _, err = client.Read(buf); err != nil {
t.Fatal(err)
}

dataRead := string(buf)
if dataRead != testData {
t.Fatalf("incorrect data read %q", dataRead)
}

if _, err = client.Read(buf); err == nil {
t.Fatal("read should fail")
}

<-serverDone
}

type CloseWriter interface {
CloseWrite() error
}
Expand Down
9 changes: 9 additions & 0 deletions zsyscall_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b29bbd5

Please sign in to comment.