mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-03 23:57:38 -04:00
add DialPipeContext
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -137,9 +138,30 @@ func (s pipeAddress) String() string {
|
|||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err := ctx.Err()
|
||||||
|
if err == context.DeadlineExceeded {
|
||||||
|
err = ErrTimeout
|
||||||
|
} else {
|
||||||
|
err = &os.PathError{Op: "open", Path: *path, Err: err}
|
||||||
|
}
|
||||||
|
return syscall.Handle(0), err
|
||||||
|
default:
|
||||||
|
h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||||
|
if err != cERROR_PIPE_BUSY {
|
||||||
|
return h, &os.PathError{Op: "open", Path: *path, Err: err}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DialPipe connects to a named pipe by path, timing out if the connection
|
// DialPipe connects to a named pipe by path, timing out if the connection
|
||||||
// takes longer than the specified duration. If timeout is nil, then we use
|
// takes longer than the specified duration. If timeout is nil, then we use
|
||||||
// a default timeout of 5 seconds. (We do not use WaitNamedPipe.)
|
// a default timeout of 2 seconds. (We do not use WaitNamedPipe.)
|
||||||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||||
var absTimeout time.Time
|
var absTimeout time.Time
|
||||||
if timeout != nil {
|
if timeout != nil {
|
||||||
@@ -147,23 +169,19 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
|||||||
} else {
|
} else {
|
||||||
absTimeout = time.Now().Add(time.Second * 2)
|
absTimeout = time.Now().Add(time.Second * 2)
|
||||||
}
|
}
|
||||||
|
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
|
||||||
|
conn, err := DialPipeContext(ctx, path)
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//DialPipeContext connects to a named pipe. ctx can be used to cancel or
|
||||||
|
//expire the pending connection ( We do not use WaitNamedPipe.)
|
||||||
|
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
|
||||||
var err error
|
var err error
|
||||||
var h syscall.Handle
|
var h syscall.Handle
|
||||||
for {
|
h, err = tryDialPipe(ctx, &path)
|
||||||
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
|
||||||
if err != cERROR_PIPE_BUSY {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if time.Now().After(absTimeout) {
|
|
||||||
return nil, ErrTimeout
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait 10 msec and try again. This is a rather simplistic
|
|
||||||
// view, as we always try each 10 milliseconds.
|
|
||||||
time.Sleep(time.Millisecond * 10)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &os.PathError{Op: "open", Path: path, Err: err}
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags uint32
|
var flags uint32
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package winio
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -37,6 +38,26 @@ func TestDialListenerTimesOut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDialListenerGetsCancelled(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
l, err := ListenPipe(testPipeName, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ch := make(chan error)
|
||||||
|
defer l.Close()
|
||||||
|
go func(ctx context.Context, ch chan error) {
|
||||||
|
_, err := DialPipeContext(ctx, testPipeName)
|
||||||
|
ch <- err
|
||||||
|
}(ctx, ch)
|
||||||
|
time.Sleep(time.Millisecond * 30)
|
||||||
|
cancel()
|
||||||
|
err = <-ch
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected ErrTimeout, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
|
func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
|
||||||
c := PipeConfig{
|
c := PipeConfig{
|
||||||
SecurityDescriptor: "D:P(A;;0x1200FF;;;WD)",
|
SecurityDescriptor: "D:P(A;;0x1200FF;;;WD)",
|
||||||
|
|||||||
Reference in New Issue
Block a user