8
8
"fmt"
9
9
"strings"
10
10
"sync"
11
+ "sync/atomic"
11
12
"time"
12
13
13
14
"github.com/btcsuite/btcd/btcec/v2"
@@ -40,8 +41,17 @@ import (
40
41
// other special cases.
41
42
const readOnlyAction = "***readonly***"
42
43
44
+ var (
45
+ // ErrServerNotActive indicates that the server has started but hasn't
46
+ // fully finished the startup process.
47
+ ErrServerNotActive = errors .New ("session server is still in the " +
48
+ "process of starting" )
49
+ )
50
+
43
51
// sessionRpcServer is the gRPC server for the Session RPC interface.
44
52
type sessionRpcServer struct {
53
+ active int32 // atomic
54
+
45
55
litrpc.UnimplementedSessionsServer
46
56
litrpc.UnimplementedFirewallServer
47
57
litrpc.UnimplementedAutopilotServer
@@ -70,41 +80,10 @@ type sessionRpcServerConfig struct {
70
80
privMap firewalldb.PrivacyMapper
71
81
}
72
82
73
- // newSessionRPCServer creates a new sessionRpcServer using the passed config.
74
- func newSessionRPCServer (cfg * sessionRpcServerConfig ) (* sessionRpcServer ,
75
- error ) {
76
-
77
- // Create the gRPC server that handles adding/removing sessions and the
78
- // actual mailbox server that spins up the Terminal Connect server
79
- // interface.
80
- server := session .NewServer (
81
- func (id session.ID , opts ... grpc.ServerOption ) * grpc.Server {
82
- // Add the session ID injector interceptors first so
83
- // that the session ID is available in the context of
84
- // all interceptors that come after.
85
- allOpts := []grpc.ServerOption {
86
- addSessionIDToStreamCtx (id ),
87
- addSessionIDToUnaryCtx (id ),
88
- }
89
-
90
- allOpts = append (allOpts , cfg .grpcOptions ... )
91
- allOpts = append (allOpts , opts ... )
92
-
93
- // Construct the gRPC server with the options.
94
- grpcServer := grpc .NewServer (allOpts ... )
95
-
96
- // Register various grpc servers with the LNC session
97
- // server.
98
- cfg .registerGrpcServers (grpcServer )
99
-
100
- return grpcServer
101
- },
102
- )
103
-
83
+ // newSessionRPCServer creates a new sessionRpcServer.
84
+ func newSessionRPCServer () (* sessionRpcServer , error ) {
104
85
return & sessionRpcServer {
105
- cfg : cfg ,
106
- sessionServer : server ,
107
- quit : make (chan struct {}),
86
+ quit : make (chan struct {}),
108
87
}, nil
109
88
}
110
89
@@ -164,9 +143,52 @@ func addSessionIDToUnaryCtx(id session.ID) grpc.ServerOption {
164
143
})
165
144
}
166
145
167
- // start all the components necessary for the sessionRpcServer to start serving
168
- // requests. This includes resuming all non-revoked sessions.
169
- func (s * sessionRpcServer ) start (ctx context.Context ) error {
146
+ // started returns true if the server has been started, and false otherwise.
147
+ // NOTE: This function is safe for concurrent access.
148
+ func (s * sessionRpcServer ) started () bool {
149
+ return atomic .LoadInt32 (& s .active ) != 0
150
+ }
151
+
152
+ // start starts a new sessionRpcServer using the passed config, and adds all
153
+ // components necessary for the sessionRpcServer to start serving requests. This
154
+ // includes resuming all non-revoked sessions.
155
+ func (s * sessionRpcServer ) start (ctx context.Context ,
156
+ cfg * sessionRpcServerConfig ) error {
157
+
158
+ if s .started () {
159
+ return errors .New ("session rpc server is already started" )
160
+ }
161
+
162
+ // Create the gRPC server that handles adding/removing sessions and the
163
+ // actual mailbox server that spins up the Terminal Connect server
164
+ // interface.
165
+ server := session .NewServer (
166
+ func (id session.ID , opts ... grpc.ServerOption ) * grpc.Server {
167
+ // Add the session ID injector interceptors first so
168
+ // that the session ID is available in the context of
169
+ // all interceptors that come after.
170
+ allOpts := []grpc.ServerOption {
171
+ addSessionIDToStreamCtx (id ),
172
+ addSessionIDToUnaryCtx (id ),
173
+ }
174
+
175
+ allOpts = append (allOpts , cfg .grpcOptions ... )
176
+ allOpts = append (allOpts , opts ... )
177
+
178
+ // Construct the gRPC server with the options.
179
+ grpcServer := grpc .NewServer (allOpts ... )
180
+
181
+ // Register various grpc servers with the LNC session
182
+ // server.
183
+ cfg .registerGrpcServers (grpcServer )
184
+
185
+ return grpcServer
186
+ },
187
+ )
188
+
189
+ s .cfg = cfg
190
+ s .sessionServer = server
191
+
170
192
// Delete all sessions in the Reserved state.
171
193
err := s .cfg .db .DeleteReservedSessions (ctx )
172
194
if err != nil {
@@ -248,14 +270,18 @@ func (s *sessionRpcServer) start(ctx context.Context) error {
248
270
}
249
271
}
250
272
273
+ atomic .StoreInt32 (& s .active , 1 )
274
+
251
275
return nil
252
276
}
253
277
254
278
// stop cleans up any sessionRpcServer resources.
255
279
func (s * sessionRpcServer ) stop () error {
256
280
var returnErr error
257
281
s .stopOnce .Do (func () {
258
- s .sessionServer .Stop ()
282
+ if s .sessionServer != nil {
283
+ s .sessionServer .Stop ()
284
+ }
259
285
260
286
close (s .quit )
261
287
s .wg .Wait ()
@@ -268,6 +294,10 @@ func (s *sessionRpcServer) stop() error {
268
294
func (s * sessionRpcServer ) AddSession (ctx context.Context ,
269
295
req * litrpc.AddSessionRequest ) (* litrpc.AddSessionResponse , error ) {
270
296
297
+ if ! s .started () {
298
+ return nil , ErrServerNotActive
299
+ }
300
+
271
301
expiry := time .Unix (int64 (req .ExpiryTimestampSeconds ), 0 )
272
302
if time .Now ().After (expiry ) {
273
303
return nil , fmt .Errorf ("expiry must be in the future" )
@@ -618,6 +648,10 @@ func (s *sessionRpcServer) resumeSession(ctx context.Context,
618
648
func (s * sessionRpcServer ) ListSessions (ctx context.Context ,
619
649
_ * litrpc.ListSessionsRequest ) (* litrpc.ListSessionsResponse , error ) {
620
650
651
+ if ! s .started () {
652
+ return nil , ErrServerNotActive
653
+ }
654
+
621
655
sessions , err := s .cfg .db .ListAllSessions (ctx )
622
656
if err != nil {
623
657
return nil , fmt .Errorf ("error fetching sessions: %v" , err )
@@ -642,6 +676,10 @@ func (s *sessionRpcServer) ListSessions(ctx context.Context,
642
676
func (s * sessionRpcServer ) RevokeSession (ctx context.Context ,
643
677
req * litrpc.RevokeSessionRequest ) (* litrpc.RevokeSessionResponse , error ) {
644
678
679
+ if ! s .started () {
680
+ return nil , ErrServerNotActive
681
+ }
682
+
645
683
pubKey , err := btcec .ParsePubKey (req .LocalPublicKey )
646
684
if err != nil {
647
685
return nil , fmt .Errorf ("error parsing public key: %v" , err )
@@ -676,6 +714,10 @@ func (s *sessionRpcServer) PrivacyMapConversion(ctx context.Context,
676
714
req * litrpc.PrivacyMapConversionRequest ) (
677
715
* litrpc.PrivacyMapConversionResponse , error ) {
678
716
717
+ if ! s .started () {
718
+ return nil , ErrServerNotActive
719
+ }
720
+
679
721
var (
680
722
groupID session.ID
681
723
err error
@@ -733,6 +775,10 @@ func (s *sessionRpcServer) PrivacyMapConversion(ctx context.Context,
733
775
func (s * sessionRpcServer ) ListActions (ctx context.Context ,
734
776
req * litrpc.ListActionsRequest ) (* litrpc.ListActionsResponse , error ) {
735
777
778
+ if ! s .started () {
779
+ return nil , ErrServerNotActive
780
+ }
781
+
736
782
// If no maximum number of actions is given, use a default of 100.
737
783
if req .MaxNumActions == 0 {
738
784
req .MaxNumActions = 100
@@ -841,6 +887,10 @@ func (s *sessionRpcServer) ListAutopilotFeatures(ctx context.Context,
841
887
_ * litrpc.ListAutopilotFeaturesRequest ) (
842
888
* litrpc.ListAutopilotFeaturesResponse , error ) {
843
889
890
+ if ! s .started () {
891
+ return nil , ErrServerNotActive
892
+ }
893
+
844
894
fs , err := s .cfg .autopilot .ListFeatures (ctx )
845
895
if err != nil {
846
896
return nil , err
@@ -884,6 +934,10 @@ func (s *sessionRpcServer) AddAutopilotSession(ctx context.Context,
884
934
req * litrpc.AddAutopilotSessionRequest ) (
885
935
* litrpc.AddAutopilotSessionResponse , error ) {
886
936
937
+ if ! s .started () {
938
+ return nil , ErrServerNotActive
939
+ }
940
+
887
941
if len (req .Features ) == 0 {
888
942
return nil , fmt .Errorf ("must include at least one feature" )
889
943
}
@@ -1325,6 +1379,10 @@ func (s *sessionRpcServer) ListAutopilotSessions(ctx context.Context,
1325
1379
_ * litrpc.ListAutopilotSessionsRequest ) (
1326
1380
* litrpc.ListAutopilotSessionsResponse , error ) {
1327
1381
1382
+ if ! s .started () {
1383
+ return nil , ErrServerNotActive
1384
+ }
1385
+
1328
1386
sessions , err := s .cfg .db .ListSessionsByType (ctx , session .TypeAutopilot )
1329
1387
if err != nil {
1330
1388
return nil , fmt .Errorf ("error fetching sessions: %v" , err )
@@ -1349,6 +1407,10 @@ func (s *sessionRpcServer) RevokeAutopilotSession(ctx context.Context,
1349
1407
req * litrpc.RevokeAutopilotSessionRequest ) (
1350
1408
* litrpc.RevokeAutopilotSessionResponse , error ) {
1351
1409
1410
+ if ! s .started () {
1411
+ return nil , ErrServerNotActive
1412
+ }
1413
+
1352
1414
pubKey , err := btcec .ParsePubKey (req .LocalPublicKey )
1353
1415
if err != nil {
1354
1416
return nil , fmt .Errorf ("error parsing public key: %v" , err )
0 commit comments