Merge pull request #4 from hanwen/master
Make Listen exclusive for a given named pipe.
diff --git a/npipe_windows.go b/npipe_windows.go
index a70a03c..bcff920 100644
--- a/npipe_windows.go
+++ b/npipe_windows.go
@@ -254,7 +254,7 @@
//
// Listen will return a PipeError for an incorrectly formatted pipe name.
func Listen(address string) (*PipeListener, error) {
- handle, err := createPipe(address)
+ handle, err := createPipe(address, true)
if err == error_invalid_name {
return nil, badAddr(address)
}
@@ -295,7 +295,7 @@
handle := l.handle
if handle == 0 {
var err error
- handle, err = createPipe(string(l.addr))
+ handle, err = createPipe(string(l.addr), false)
if err != nil {
return nil, err
}
@@ -459,16 +459,21 @@
return string(a)
}
-// createPipe is a helper function to make sure we always create pipes with the same arguments,
-// since subsequent calls to create pipe need to use the same arguments as the first one.
-func createPipe(address string) (syscall.Handle, error) {
+// createPipe is a helper function to make sure we always create pipes
+// with the same arguments, since subsequent calls to create pipe need
+// to use the same arguments as the first one. If first is set, fail
+// if the pipe already exists.
+func createPipe(address string, first bool) (syscall.Handle, error) {
n, err := syscall.UTF16PtrFromString(address)
if err != nil {
return 0, err
}
-
+ mode := uint32(pipe_access_duplex | syscall.FILE_FLAG_OVERLAPPED)
+ if first {
+ mode |= file_flag_first_pipe_instance
+ }
return createNamedPipe(n,
- pipe_access_duplex|syscall.FILE_FLAG_OVERLAPPED,
+ mode,
pipe_type_byte,
pipe_unlimited_instances,
512, 512, 0, nil)
diff --git a/npipe_windows_test.go b/npipe_windows_test.go
index d8f5df7..3aadf95 100644
--- a/npipe_windows_test.go
+++ b/npipe_windows_test.go
@@ -77,6 +77,22 @@
}
}
+// TestDoubleListen makes sure we can't listen to the same address twice.
+func TestDoubleListen(t *testing.T) {
+ address := `\\.\pipe\TestDoubleListen`
+ ln1, err := Listen(address)
+ if err != nil {
+ t.Fatalf("Listen(%q): %v", address, err)
+ }
+ defer ln1.Close()
+
+ ln2, err := Listen(address)
+ if err == nil {
+ ln2.Close()
+ t.Fatalf("second Listen on %q succeeded.", address)
+ }
+}
+
// Test that PipeConn's read deadline works correctly
func TestReadDeadline(t *testing.T) {
address := `\\.\pipe\TestReadDeadline`
@@ -333,6 +349,13 @@
// and then dial into it with several clients in succession
func TestCommonUseCase(t *testing.T) {
addrs := []string{`\\.\pipe\TestCommonUseCase`, `\\127.0.0.1\pipe\TestCommonUseCase`}
+ // always listen on the . version, since IP won't work for listening
+ ln, err := Listen(addrs[0])
+ if err != nil {
+ t.Fatalf("Listen(%q) failed: %v", addrs[0], err)
+ }
+ defer ln.Close()
+
for _, address := range addrs {
convos := 5
clients := 10
@@ -342,12 +365,6 @@
go aggregateDones(done, quit, clients)
- // always listen on the . version, since IP won't work for listening
- ln, err := Listen(addrs[0])
- if err != nil {
- t.Fatal("Error starting to listen on pipe: ", err)
- }
-
for x := 0; x < clients; x++ {
go startClient(address, done, convos, t)
}