Commit eb88b3ee authored by Russ Cox's avatar Russ Cox

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: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 13558c41
...@@ -190,6 +190,18 @@ func (ln *UnixListener) file() (*os.File, error) { ...@@ -190,6 +190,18 @@ func (ln *UnixListener) file() (*os.File, error) {
return f, nil 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) { func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
fd, err := unixSocket(ctx, network, laddr, nil, "listen") fd, err := unixSocket(ctx, network, laddr, nil, "listen")
if err != nil { if err != nil {
......
...@@ -415,44 +415,104 @@ func TestUnixUnlink(t *testing.T) { ...@@ -415,44 +415,104 @@ func TestUnixUnlink(t *testing.T) {
t.Skip("unix test") t.Skip("unix test")
} }
name := testUnixAddr() name := testUnixAddr()
listen := func(t *testing.T) *UnixListener {
l, err := Listen("unix", name) l, err := Listen("unix", name)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, err := os.Stat(name); err != nil { return l.(*UnixListener)
t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
}
f, _ := l.(*UnixListener).File()
l1, err := FileListener(f)
if err != nil {
t.Fatal(err)
} }
checkExists := func(t *testing.T, desc string) {
if _, err := os.Stat(name); err != nil { if _, err := os.Stat(name); err != nil {
t.Fatalf("cannot stat unix socket after FileListener: %v", err) t.Fatalf("unix socket does not exist %s: %v", desc, err)
} }
if err := l1.Close(); err != nil {
t.Fatalf("closing file listener: %v", err)
} }
if _, err := os.Stat(name); err != nil { checkNotExists := func(t *testing.T, desc string) {
t.Fatalf("cannot stat unix socket after closing FileListener: %v", err) if _, err := os.Stat(name); err == nil {
t.Fatalf("unix socket does exist %s: %v", desc, err)
} }
f.Close()
if _, err := os.Stat(name); err != nil {
t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
} }
// Listener should remove on close.
t.Run("Listen", func(t *testing.T) {
l := listen(t)
checkExists(t, "after Listen")
l.Close() l.Close()
if _, err := os.Stat(name); err == nil { checkNotExists(t, "after Listener close")
t.Fatal("closing unix listener did not remove unix socket") })
}
// 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 { if err := ioutil.WriteFile(name, []byte("hello world"), 0666); err != nil {
t.Fatalf("cannot recreate socket file: %v", err) t.Fatalf("cannot recreate socket file: %v", err)
} }
if _, err := os.Stat(name); err != nil { checkExists(t, "after writing temp file")
t.Fatal("recreating unix listener as file failed: %v", err)
}
l.Close() l.Close()
if _, err := os.Stat(name); err != nil { checkExists(t, "after second Listener close")
t.Fatalf("second close of unix socket did second remove: %v", err)
}
os.Remove(name) 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()
})
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment