@@ -67,6 +67,7 @@ type Server struct {
67
67
proto.UnimplementedDaemonServiceServer
68
68
clientRunning bool // protected by mutex
69
69
clientRunningChan chan struct {}
70
+ clientGiveUpChan chan struct {}
70
71
71
72
connectClient * internal.ConnectClient
72
73
@@ -106,6 +107,10 @@ func (s *Server) Start() error {
106
107
s .mutex .Lock ()
107
108
defer s .mutex .Unlock ()
108
109
110
+ if s .clientRunning {
111
+ return nil
112
+ }
113
+
109
114
state := internal .CtxGetState (s .rootCtx )
110
115
111
116
if err := handlePanicLog (); err != nil {
@@ -175,12 +180,10 @@ func (s *Server) Start() error {
175
180
return nil
176
181
}
177
182
178
- if s .clientRunning {
179
- return nil
180
- }
181
183
s .clientRunning = true
182
- s .clientRunningChan = make (chan struct {}, 1 )
183
- go s .connectWithRetryRuns (ctx , config , s .statusRecorder , s .clientRunningChan )
184
+ s .clientRunningChan = make (chan struct {})
185
+ s .clientGiveUpChan = make (chan struct {})
186
+ go s .connectWithRetryRuns (ctx , config , s .statusRecorder , s .clientRunningChan , s .clientGiveUpChan )
184
187
return nil
185
188
}
186
189
@@ -211,7 +214,7 @@ func (s *Server) setDefaultConfigIfNotExists(ctx context.Context) error {
211
214
// connectWithRetryRuns runs the client connection with a backoff strategy where we retry the operation as additional
212
215
// mechanism to keep the client connected even when the connection is lost.
213
216
// we cancel retry if the client receive a stop or down command, or if disable auto connect is configured.
214
- func (s * Server ) connectWithRetryRuns (ctx context.Context , profileConfig * profilemanager.Config , statusRecorder * peer.Status , runningChan chan struct {}) {
217
+ func (s * Server ) connectWithRetryRuns (ctx context.Context , profileConfig * profilemanager.Config , statusRecorder * peer.Status , runningChan chan struct {}, giveUpChan chan struct {} ) {
215
218
defer func () {
216
219
s .mutex .Lock ()
217
220
s .clientRunning = false
@@ -261,6 +264,10 @@ func (s *Server) connectWithRetryRuns(ctx context.Context, profileConfig *profil
261
264
if err := backoff .Retry (runOperation , backOff ); err != nil {
262
265
log .Errorf ("operation failed: %v" , err )
263
266
}
267
+
268
+ if giveUpChan != nil {
269
+ close (giveUpChan )
270
+ }
264
271
}
265
272
266
273
// loginAttempt attempts to login using the provided information. it returns a status in case something fails
@@ -379,7 +386,7 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
379
386
if s .actCancel != nil {
380
387
s .actCancel ()
381
388
}
382
- ctx , cancel := context .WithCancel (s . rootCtx )
389
+ ctx , cancel := context .WithCancel (callerCtx )
383
390
384
391
md , ok := metadata .FromIncomingContext (callerCtx )
385
392
if ok {
@@ -389,11 +396,11 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
389
396
s .actCancel = cancel
390
397
s .mutex .Unlock ()
391
398
392
- if err := restoreResidualState (ctx , s .profileManager .GetStatePath ()); err != nil {
399
+ if err := restoreResidualState (s . rootCtx , s .profileManager .GetStatePath ()); err != nil {
393
400
log .Warnf (errRestoreResidualState , err )
394
401
}
395
402
396
- state := internal .CtxGetState (ctx )
403
+ state := internal .CtxGetState (s . rootCtx )
397
404
defer func () {
398
405
status , err := state .Status ()
399
406
if err != nil || (status != internal .StatusNeedsLogin && status != internal .StatusLoginFailed ) {
@@ -606,6 +613,20 @@ func (s *Server) WaitSSOLogin(callerCtx context.Context, msg *proto.WaitSSOLogin
606
613
// Up starts engine work in the daemon.
607
614
func (s * Server ) Up (callerCtx context.Context , msg * proto.UpRequest ) (* proto.UpResponse , error ) {
608
615
s .mutex .Lock ()
616
+ if s .clientRunning {
617
+ state := internal .CtxGetState (s .rootCtx )
618
+ status , err := state .Status ()
619
+ if err != nil {
620
+ s .mutex .Unlock ()
621
+ return nil , err
622
+ }
623
+ if status == internal .StatusNeedsLogin {
624
+ s .actCancel ()
625
+ }
626
+ s .mutex .Unlock ()
627
+
628
+ return s .waitForUp (callerCtx )
629
+ }
609
630
defer s .mutex .Unlock ()
610
631
611
632
if err := restoreResidualState (callerCtx , s .profileManager .GetStatePath ()); err != nil {
@@ -621,16 +642,16 @@ func (s *Server) Up(callerCtx context.Context, msg *proto.UpRequest) (*proto.UpR
621
642
if err != nil {
622
643
return nil , err
623
644
}
645
+
624
646
if status != internal .StatusIdle {
625
647
return nil , fmt .Errorf ("up already in progress: current status %s" , status )
626
648
}
627
649
628
- // it should be nil here, but .
650
+ // it should be nil here, but in case it isn't we cancel it .
629
651
if s .actCancel != nil {
630
652
s .actCancel ()
631
653
}
632
654
ctx , cancel := context .WithCancel (s .rootCtx )
633
-
634
655
md , ok := metadata .FromIncomingContext (callerCtx )
635
656
if ok {
636
657
ctx = metadata .NewOutgoingContext (ctx , md )
@@ -673,26 +694,31 @@ func (s *Server) Up(callerCtx context.Context, msg *proto.UpRequest) (*proto.UpR
673
694
s .statusRecorder .UpdateManagementAddress (s .config .ManagementURL .String ())
674
695
s .statusRecorder .UpdateRosenpass (s .config .RosenpassEnabled , s .config .RosenpassPermissive )
675
696
697
+ s .clientRunning = true
698
+ s .clientRunningChan = make (chan struct {})
699
+ s .clientGiveUpChan = make (chan struct {})
700
+ go s .connectWithRetryRuns (ctx , s .config , s .statusRecorder , s .clientRunningChan , s .clientGiveUpChan )
701
+
702
+ return s .waitForUp (callerCtx )
703
+ }
704
+
705
+ // todo: handle potential race conditions
706
+ func (s * Server ) waitForUp (callerCtx context.Context ) (* proto.UpResponse , error ) {
676
707
timeoutCtx , cancel := context .WithTimeout (callerCtx , 50 * time .Second )
677
708
defer cancel ()
678
709
679
- if ! s .clientRunning {
680
- s .clientRunning = true
681
- s .clientRunningChan = make (chan struct {}, 1 )
682
- go s .connectWithRetryRuns (ctx , s .config , s .statusRecorder , s .clientRunningChan )
683
- }
684
- for {
685
- select {
686
- case <- s .clientRunningChan :
687
- s .isSessionActive .Store (true )
688
- return & proto.UpResponse {}, nil
689
- case <- callerCtx .Done ():
690
- log .Debug ("context done, stopping the wait for engine to become ready" )
691
- return nil , callerCtx .Err ()
692
- case <- timeoutCtx .Done ():
693
- log .Debug ("up is timed out, stopping the wait for engine to become ready" )
694
- return nil , timeoutCtx .Err ()
695
- }
710
+ select {
711
+ case <- s .clientGiveUpChan :
712
+ return nil , fmt .Errorf ("client gave up to connect" )
713
+ case <- s .clientRunningChan :
714
+ s .isSessionActive .Store (true )
715
+ return & proto.UpResponse {}, nil
716
+ case <- callerCtx .Done ():
717
+ log .Debug ("context done, stopping the wait for engine to become ready" )
718
+ return nil , callerCtx .Err ()
719
+ case <- timeoutCtx .Done ():
720
+ log .Debug ("up is timed out, stopping the wait for engine to become ready" )
721
+ return nil , timeoutCtx .Err ()
696
722
}
697
723
}
698
724
@@ -966,12 +992,46 @@ func (s *Server) Status(
966
992
ctx context.Context ,
967
993
msg * proto.StatusRequest ,
968
994
) (* proto.StatusResponse , error ) {
969
- if ctx .Err () != nil {
970
- return nil , ctx .Err ()
971
- }
972
-
973
995
s .mutex .Lock ()
974
- defer s .mutex .Unlock ()
996
+ clientRunning := s .clientRunning
997
+ s .mutex .Unlock ()
998
+
999
+ if msg .WaitForReady != nil && * msg .WaitForReady && clientRunning {
1000
+ state := internal .CtxGetState (s .rootCtx )
1001
+ status , err := state .Status ()
1002
+ if err != nil {
1003
+ return nil , err
1004
+ }
1005
+
1006
+ if status != internal .StatusIdle && status != internal .StatusConnected && status != internal .StatusConnecting {
1007
+ s .actCancel ()
1008
+ }
1009
+
1010
+ ticker := time .NewTicker (1 * time .Second )
1011
+ defer ticker .Stop ()
1012
+ loop:
1013
+ for {
1014
+ select {
1015
+ case <- s .clientGiveUpChan :
1016
+ ticker .Stop ()
1017
+ break loop
1018
+ case <- s .clientRunningChan :
1019
+ ticker .Stop ()
1020
+ break loop
1021
+ case <- ticker .C :
1022
+ status , err := state .Status ()
1023
+ if err != nil {
1024
+ continue
1025
+ }
1026
+ if status != internal .StatusIdle && status != internal .StatusConnected && status != internal .StatusConnecting {
1027
+ s .actCancel ()
1028
+ }
1029
+ continue
1030
+ case <- ctx .Done ():
1031
+ return nil , ctx .Err ()
1032
+ }
1033
+ }
1034
+ }
975
1035
976
1036
status , err := internal .CtxGetState (s .rootCtx ).Status ()
977
1037
if err != nil {
0 commit comments