@@ -26,13 +26,15 @@ package netstack
2626import (
2727 "fmt"
2828 "strconv"
29+ "sync"
30+ "sync/atomic"
2931 "syscall"
3032
3133 "github.com/celzero/firestack/intra/log"
3234 "golang.org/x/sys/unix"
3335)
3436
35- var invalidFds = & fds {stopFd {efd : invalidfd }, invalidfd }
37+ var invalidFds = & fds {stopFd : stopFd {efd : invalidfd }, tunFd : invalidfd }
3638
3739// stopFd is an eventfd used to signal the stop of a dispatcher.
3840type stopFd struct {
@@ -67,6 +69,9 @@ func (s *stopFd) stop() error {
6769type fds struct {
6870 stopFd stopFd
6971 tunFd int
72+
73+ closed atomic.Bool
74+ once sync.Once // ensures that stop() is called only once
7075}
7176
7277// Takes ownership of fd, which must be a valid TUN file descriptor.
@@ -85,11 +90,11 @@ func newTun(fd int) (*fds, error) {
8590 clos (fd )
8691 return invalidFds , err
8792 }
88- return & fds {stopFd , fd }, nil
93+ return & fds {stopFd : stopFd , tunFd : fd }, nil
8994}
9095
9196func (f * fds ) ok () bool {
92- return f != nil && f .tun () != invalidfd
97+ return f != nil && f .tun () != invalidfd && ! f . closed . Load ()
9398}
9499
95100func (f * fds ) eve () int {
@@ -108,10 +113,14 @@ func (f *fds) tun() int {
108113
109114func (f * fds ) stop () {
110115 if f .ok () {
111- err1 := f .stopFd .stop ()
112- err2 := syscall .Close (f .tunFd )
113- logeif (err1 )("ns: dispatch: fds: stop: eve(%d) tun(%d); errs? %v %v" ,
114- f .stopFd .efd , f .tunFd , err1 , err2 )
116+ f .once .Do (func () {
117+ defer f .closed .Store (true )
118+
119+ err1 := f .stopFd .stop ()
120+ err2 := syscall .Close (f .tunFd )
121+ logeif (err1 )("ns: dispatch: fds: stop: eve(%d) tun(%d); errs? %v %v" ,
122+ f .stopFd .efd , f .tunFd , err1 , err2 )
123+ })
115124 } else {
116125 log .W ("ns: dispatch: fds: stop: no-op" )
117126 }
0 commit comments