• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/signal/signal.go
1
// Copyright (c) 2013-2017 The btcsuite developers
2
// Copyright (c) 2015-2016 The Decred developers
3
// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go
4
// Copyright (C) 2015-2022 The Lightning Network Developers
5

6
package signal
7

8
import (
9
        "errors"
10
        "fmt"
11
        "os"
12
        "os/signal"
13
        "sync/atomic"
14
        "syscall"
15

16
        "github.com/coreos/go-systemd/daemon"
17
)
18

19
var (
20
        // started indicates whether we have started our main interrupt handler.
21
        // This field should be used atomically.
22
        started int32
23
)
24

25
// systemdNotifyReady notifies systemd about LND being ready, logs the result of
26
// the operation or possible error. Besides logging, systemd being unavailable
27
// is ignored.
UNCOV
28
func systemdNotifyReady() error {
×
UNCOV
29
        notified, err := daemon.SdNotify(false, daemon.SdNotifyReady)
×
UNCOV
30
        if err != nil {
×
31
                err := fmt.Errorf("failed to notify systemd %v (if you aren't "+
×
32
                        "running systemd clear the environment variable "+
×
33
                        "NOTIFY_SOCKET)", err)
×
34
                log.Error(err)
×
35

×
36
                // The SdNotify doc says it's common to ignore the
×
37
                // error. We don't want to ignore it because if someone
×
38
                // set up systemd to wait for initialization other
×
39
                // processes would get stuck.
×
40
                return err
×
41
        }
×
UNCOV
42
        if notified {
×
43
                log.Info("Systemd was notified about our readiness")
×
UNCOV
44
        } else {
×
UNCOV
45
                log.Info("We're not running within systemd or the service " +
×
UNCOV
46
                        "type is not 'notify'")
×
UNCOV
47
        }
×
UNCOV
48
        return nil
×
49
}
50

51
// systemdNotifyStop notifies systemd that LND is stopping and logs error if
52
// the notification failed. It also logs if the notification was actually sent.
53
// Systemd being unavailable is intentionally ignored.
UNCOV
54
func systemdNotifyStop() {
×
UNCOV
55
        notified, err := daemon.SdNotify(false, daemon.SdNotifyStopping)
×
UNCOV
56

×
UNCOV
57
        // Just log - we're stopping anyway.
×
UNCOV
58
        if err != nil {
×
59
                log.Errorf("Failed to notify systemd: %v", err)
×
60
        }
×
UNCOV
61
        if notified {
×
62
                log.Infof("Systemd was notified about stopping")
×
63
        }
×
64
}
65

66
// Notifier handles notifications about status of LND.
67
type Notifier struct {
68
        // notifiedReady remembers whether Ready was sent to avoid sending it
69
        // multiple times.
70
        notifiedReady bool
71
}
72

73
// NotifyReady notifies other applications that RPC is ready.
UNCOV
74
func (notifier *Notifier) NotifyReady(walletUnlocked bool) error {
×
UNCOV
75
        if !notifier.notifiedReady {
×
UNCOV
76
                err := systemdNotifyReady()
×
UNCOV
77
                if err != nil {
×
78
                        return err
×
79
                }
×
UNCOV
80
                notifier.notifiedReady = true
×
81
        }
UNCOV
82
        if walletUnlocked {
×
UNCOV
83
                _, _ = daemon.SdNotify(false, "STATUS=Wallet unlocked")
×
UNCOV
84
        } else {
×
UNCOV
85
                _, _ = daemon.SdNotify(false, "STATUS=Wallet locked")
×
UNCOV
86
        }
×
87

UNCOV
88
        return nil
×
89
}
90

91
// notifyStop notifies other applications that LND is stopping.
UNCOV
92
func (notifier *Notifier) notifyStop() {
×
UNCOV
93
        systemdNotifyStop()
×
UNCOV
94
}
×
95

96
// Interceptor contains channels and methods regarding application shutdown
97
// and interrupt signals.
98
type Interceptor struct {
99
        // interruptChannel is used to receive SIGINT (Ctrl+C) signals.
100
        interruptChannel chan os.Signal
101

102
        // shutdownChannel is closed once the main interrupt handler exits.
103
        shutdownChannel chan struct{}
104

105
        // shutdownRequestChannel is used to request the daemon to shutdown
106
        // gracefully, similar to when receiving SIGINT.
107
        shutdownRequestChannel chan struct{}
108

109
        // quit is closed when instructing the main interrupt handler to exit.
110
        // Note that to avoid losing notifications, only shutdown func may
111
        // close this channel.
112
        quit chan struct{}
113

114
        // Notifier handles sending shutdown notifications.
115
        Notifier Notifier
116
}
117

118
// Intercept starts the interception of interrupt signals and returns an `Interceptor` instance.
119
// Note that any previous active interceptor must be stopped before a new one can be created.
UNCOV
120
func Intercept() (Interceptor, error) {
×
UNCOV
121
        if !atomic.CompareAndSwapInt32(&started, 0, 1) {
×
122
                return Interceptor{}, errors.New("intercept already started")
×
123
        }
×
124

UNCOV
125
        channels := Interceptor{
×
UNCOV
126
                interruptChannel:       make(chan os.Signal, 1),
×
UNCOV
127
                shutdownChannel:        make(chan struct{}),
×
UNCOV
128
                shutdownRequestChannel: make(chan struct{}),
×
UNCOV
129
                quit:                   make(chan struct{}),
×
UNCOV
130
        }
×
UNCOV
131

×
UNCOV
132
        signalsToCatch := []os.Signal{
×
UNCOV
133
                os.Interrupt,
×
UNCOV
134
                os.Kill,
×
UNCOV
135
                syscall.SIGTERM,
×
UNCOV
136
                syscall.SIGQUIT,
×
UNCOV
137
        }
×
UNCOV
138
        signal.Notify(channels.interruptChannel, signalsToCatch...)
×
UNCOV
139
        go channels.mainInterruptHandler()
×
UNCOV
140

×
UNCOV
141
        return channels, nil
×
142
}
143

144
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
145
// interruptChannel and shutdown requests on the shutdownRequestChannel, and
146
// invokes the registered interruptCallbacks accordingly. It also listens for
147
// callback registration.
148
// It must be run as a goroutine.
UNCOV
149
func (c *Interceptor) mainInterruptHandler() {
×
UNCOV
150
        defer atomic.StoreInt32(&started, 0)
×
UNCOV
151
        // isShutdown is a flag which is used to indicate whether or not
×
UNCOV
152
        // the shutdown signal has already been received and hence any future
×
UNCOV
153
        // attempts to add a new interrupt handler should invoke them
×
UNCOV
154
        // immediately.
×
UNCOV
155
        var isShutdown bool
×
UNCOV
156

×
UNCOV
157
        // shutdown invokes the registered interrupt handlers, then signals the
×
UNCOV
158
        // shutdownChannel.
×
UNCOV
159
        shutdown := func() {
×
UNCOV
160
                // Ignore more than one shutdown signal.
×
UNCOV
161
                if isShutdown {
×
162
                        log.Infof("Already shutting down...")
×
163
                        return
×
164
                }
×
UNCOV
165
                isShutdown = true
×
UNCOV
166
                log.Infof("Shutting down...")
×
UNCOV
167
                c.Notifier.notifyStop()
×
UNCOV
168

×
UNCOV
169
                // Signal the main interrupt handler to exit, and stop accept
×
UNCOV
170
                // post-facto requests.
×
UNCOV
171
                close(c.quit)
×
172
        }
173

UNCOV
174
        for {
×
UNCOV
175
                select {
×
176
                case signal := <-c.interruptChannel:
×
177
                        log.Infof("Received %v", signal)
×
178
                        shutdown()
×
179

UNCOV
180
                case <-c.shutdownRequestChannel:
×
UNCOV
181
                        log.Infof("Received shutdown request.")
×
UNCOV
182
                        shutdown()
×
183

UNCOV
184
                case <-c.quit:
×
UNCOV
185
                        log.Infof("Gracefully shutting down.")
×
UNCOV
186
                        close(c.shutdownChannel)
×
UNCOV
187
                        signal.Stop(c.interruptChannel)
×
UNCOV
188
                        return
×
189
                }
190
        }
191
}
192

193
// Listening returns true if the main interrupt handler has been started, and
194
// has not been killed.
UNCOV
195
func (c *Interceptor) Listening() bool {
×
UNCOV
196
        // If our started field is not set, we are not yet listening for
×
UNCOV
197
        // interrupts.
×
UNCOV
198
        if atomic.LoadInt32(&started) != 1 {
×
199
                return false
×
200
        }
×
201

202
        // If we have started our main goroutine, we check whether we have
203
        // stopped it yet.
UNCOV
204
        return c.Alive()
×
205
}
206

207
// Alive returns true if the main interrupt handler has not been killed.
UNCOV
208
func (c *Interceptor) Alive() bool {
×
UNCOV
209
        select {
×
210
        case <-c.quit:
×
211
                return false
×
UNCOV
212
        default:
×
UNCOV
213
                return true
×
214
        }
215
}
216

217
// RequestShutdown initiates a graceful shutdown from the application.
UNCOV
218
func (c *Interceptor) RequestShutdown() {
×
UNCOV
219
        select {
×
UNCOV
220
        case c.shutdownRequestChannel <- struct{}{}:
×
221
        case <-c.quit:
×
222
        }
223
}
224

225
// ShutdownChannel returns the channel that will be closed once the main
226
// interrupt handler has exited.
UNCOV
227
func (c *Interceptor) ShutdownChannel() <-chan struct{} {
×
UNCOV
228
        return c.shutdownChannel
×
UNCOV
229
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc