]> Cypherpunks repositories - gostls13.git/commitdiff
net: add (*UnixListener).SetUnlinkOnClose
authorRuss Cox <rsc@golang.org>
Thu, 27 Oct 2016 00:23:03 +0000 (20:23 -0400)
committerRuss Cox <rsc@golang.org>
Fri, 28 Oct 2016 18:29:35 +0000 (18:29 +0000)
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>
src/net/unixsock_posix.go
src/net/unixsock_test.go

index 7e70c8f8ed77e130f870d86826f515748ca675dd..1ab7cbe2225c05c1a02aec2f8c1bda32f6dd2bff 100644 (file)
@@ -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 {
index 015036770b55e1a134b09fc782baceddfedc64c4..489a29bc7d7c224bc7cde5fc09e594d138cb8e1b 100644 (file)
@@ -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()
+       })
 }