From: Russ Cox Date: Thu, 27 Oct 2016 00:23:03 +0000 (-0400) Subject: net: add (*UnixListener).SetUnlinkOnClose X-Git-Tag: go1.8beta1~507 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=eb88b3eefa113f67e7cf72dfd085f65bbd125179;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- 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() + }) }