aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2016-10-26 20:23:03 -0400
committerRuss Cox <rsc@golang.org>2016-10-28 18:29:35 +0000
commiteb88b3eefa113f67e7cf72dfd085f65bbd125179 (patch)
treea2ad61fea369f458aef4b39074e51757c652963b
parent13558c41ffa29d0af80e7e06d08af8eb0f0055fb (diff)
downloadgo-eb88b3eefa113f67e7cf72dfd085f65bbd125179.tar.xz
net: add (*UnixListener).SetUnlinkOnClose
Let users control whether unix listener socket file is unlinked on close. Fixes #13877. Change-Id: I9d1cb47e31418d655f164d15c67e188656a67d1c Reviewed-on: https://go-review.googlesource.com/32099 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
-rw-r--r--src/net/unixsock_posix.go12
-rw-r--r--src/net/unixsock_test.go134
2 files changed, 109 insertions, 37 deletions
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 7e70c8f8ed..1ab7cbe222 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -190,6 +190,18 @@ func (ln *UnixListener) file() (*os.File, error) {
return f, nil
}
+// SetUnlinkOnClose sets whether the underlying socket file should be removed
+// from the file system when the listener is closed.
+//
+// The default behavior is to unlink the socket file only when package net created it.
+// That is, when the listener and the underlying socket file were created by a call to
+// Listen or ListenUnix, then by default closing the listener will remove the socket file.
+// but if the listener was created by a call to FileListener to use an already existing
+// socket file, then by default closing the listener will not remove the socket file.
+func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
+ l.unlink = unlink
+}
+
func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
fd, err := unixSocket(ctx, network, laddr, nil, "listen")
if err != nil {
diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go
index 015036770b..489a29bc7d 100644
--- a/src/net/unixsock_test.go
+++ b/src/net/unixsock_test.go
@@ -415,44 +415,104 @@ func TestUnixUnlink(t *testing.T) {
t.Skip("unix test")
}
name := testUnixAddr()
- l, err := Listen("unix", name)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
- }
- f, _ := l.(*UnixListener).File()
- l1, err := FileListener(f)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after FileListener: %v", err)
- }
- if err := l1.Close(); err != nil {
- t.Fatalf("closing file listener: %v", err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
- }
- f.Close()
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
- }
- l.Close()
- if _, err := os.Stat(name); err == nil {
- t.Fatal("closing unix listener did not remove unix socket")
- }
- if err := ioutil.WriteFile(name, []byte("hello world"), 0666); err != nil {
- t.Fatalf("cannot recreate socket file: %v", err)
+
+ listen := func(t *testing.T) *UnixListener {
+ l, err := Listen("unix", name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return l.(*UnixListener)
}
- if _, err := os.Stat(name); err != nil {
- t.Fatal("recreating unix listener as file failed: %v", err)
+ checkExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err != nil {
+ t.Fatalf("unix socket does not exist %s: %v", desc, err)
+ }
}
- l.Close()
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("second close of unix socket did second remove: %v", err)
+ checkNotExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err == nil {
+ t.Fatalf("unix socket does exist %s: %v", desc, err)
+ }
}
- os.Remove(name)
+
+ // Listener should remove on close.
+ t.Run("Listen", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // FileListener should not.
+ t.Run("FileListener", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // Only first call to l.Close should remove.
+ t.Run("SecondClose", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ if err := ioutil.WriteFile(name, []byte("hello world"), 0666); err != nil {
+ t.Fatalf("cannot recreate socket file: %v", err)
+ }
+ checkExists(t, "after writing temp file")
+ l.Close()
+ checkExists(t, "after second Listener close")
+ os.Remove(name)
+ })
+
+ // SetUnlinkOnClose should do what it says.
+
+ t.Run("Listen/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(true)
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ t.Run("Listen/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(false)
+ l.Close()
+ checkExists(t, "after Listener close")
+ os.Remove(name)
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(true)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkNotExists(t, "after FileListener close")
+ l.Close()
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(false)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ })
}