2
2
package netutil
3
3
4
4
import (
5
- "context"
6
5
"fmt"
7
6
"net"
8
7
"os"
@@ -19,63 +18,49 @@ var (
19
18
allowEveryone = osutil .FileMode (osutil .OwnerRW , osutil .GroupRW , osutil .OtherRW )
20
19
)
21
20
22
- func ListenUnixAllowOwner (ctx context. Context , sockPath string , with func (net.Listener ) error ) error {
23
- return ListenUnixWithMode (ctx , sockPath , & allowOwner , with )
21
+ func ListenUnixAllowOwner (sockPath string , with func (net.Listener ) error ) error {
22
+ return ListenUnixWithMode (sockPath , & allowOwner , with )
24
23
}
25
24
26
- func ListenUnixAllowOwnerAndGroup (ctx context. Context , sockPath string , with func (net.Listener ) error ) error {
27
- return ListenUnixWithMode (ctx , sockPath , & allowOwnerAndGroup , with )
25
+ func ListenUnixAllowOwnerAndGroup (sockPath string , with func (net.Listener ) error ) error {
26
+ return ListenUnixWithMode (sockPath , & allowOwnerAndGroup , with )
28
27
}
29
28
30
- func ListenUnixAllowEveryone (ctx context. Context , sockPath string , with func (net.Listener ) error ) error {
31
- return ListenUnixWithMode (ctx , sockPath , & allowEveryone , with )
29
+ func ListenUnixAllowEveryone (sockPath string , with func (net.Listener ) error ) error {
30
+ return ListenUnixWithMode (sockPath , & allowEveryone , with )
32
31
}
33
32
34
33
// pass nil os.FileMode if you don't want to Chmod() the socket file
35
- func ListenUnixWithMode (
36
- ctx context. Context ,
37
- sockPath string ,
38
- mode * os.FileMode ,
39
- with func (net. Listener ) error ,
40
- ) error {
34
+ //
35
+ // NOTE: `with()` is responsible for closing the obtained listener. for example the HTTP server
36
+ // launched from `with()` must be able to do graceful shutdown and `http.Server.Serve()` always closes the listener.
37
+ func ListenUnixWithMode ( sockPath string , mode * os.FileMode , with func (net. Listener ) error ) error {
38
+ withErr := func (err error ) error { return fmt . Errorf ( "ListenUnix: %w" , err ) }
39
+
41
40
exists , err := osutil .Exists (sockPath )
42
41
if err != nil {
43
- return fmt .Errorf ("ListenUnix: exists: %w" , err )
42
+ return withErr ( fmt .Errorf ("exists: %w" , err ) )
44
43
}
45
44
46
45
// clean-up old socket
47
46
if exists {
48
47
if err := os .Remove (sockPath ); err != nil {
49
- return fmt .Errorf ("ListenUnix: cleanup previous: %w" , err )
48
+ return withErr ( fmt .Errorf ("cleanup previous socket : %w" , err ) )
50
49
}
51
50
}
52
51
53
52
listener , err := net .Listen ("unix" , sockPath )
54
53
if err != nil {
55
- return fmt . Errorf ( "ListenUnix: %w" , err )
54
+ return withErr ( err )
56
55
}
57
56
58
57
defer func () { // socket file was created. cleanup, so hopefully the next user doesn't need os.Remove()
59
58
_ = os .Remove (sockPath )
60
59
}()
61
60
62
- listenerCtx , cancel := context .WithCancel (ctx ) // explained in next block
63
- defer cancel ()
64
-
65
- // stop listener when:
66
- //
67
- // a) parent ctx done
68
- // b) we're exiting due to Chmod() failing
69
- // c) with() exits due to listener not closed but Accept() failing (kinda grey area - can that happen?)
70
- // ^ this signalled by defer cancel()
71
- go func () {
72
- <- listenerCtx .Done ()
73
- listener .Close ()
74
- }()
75
-
76
61
if mode != nil {
77
62
if err := os .Chmod (sockPath , * mode ); err != nil {
78
- return fmt . Errorf ( "ListenUnix: %w" , err )
63
+ return withErr ( err )
79
64
}
80
65
}
81
66
0 commit comments