diff --git a/hub/executor/executor.go b/hub/executor/executor.go index c6bef525..fcf176e0 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -231,6 +231,8 @@ func updateNTP(c *config.NTP) { c.DialerProxy, c.WriteToSystem, ) + } else { + ntp.ReCreateNTPService("", 0, "", false) } } diff --git a/ntp/service.go b/ntp/service.go index 6fb7453e..76290359 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -3,6 +3,7 @@ package ntp import ( "context" "sync" + "sync/atomic" "time" "github.com/metacubex/mihomo/component/dialer" @@ -13,8 +14,8 @@ import ( "github.com/metacubex/sing/common/ntp" ) -var offset time.Duration -var service *Service +var globalSrv atomic.Pointer[Service] +var globalMu sync.Mutex type Service struct { server M.Socksaddr @@ -22,15 +23,20 @@ type Service struct { ticker *time.Ticker ctx context.Context cancel context.CancelFunc - mu sync.Mutex + offset atomic.Int64 // [time.Duration] syncSystemTime bool - running bool } func ReCreateNTPService(server string, interval time.Duration, dialerProxy string, syncSystemTime bool) { + globalMu.Lock() + defer globalMu.Unlock() + service := globalSrv.Swap(nil) if service != nil { service.Stop() } + if server == "" { + return + } ctx, cancel := context.WithCancel(context.Background()) service = &Service{ server: M.ParseSocksaddr(server), @@ -41,87 +47,76 @@ func ReCreateNTPService(server string, interval time.Duration, dialerProxy strin syncSystemTime: syncSystemTime, } service.Start() + globalSrv.Store(service) } func (srv *Service) Start() { - srv.mu.Lock() - defer srv.mu.Unlock() log.Infoln("NTP service start, sync system time is %t", srv.syncSystemTime) - err := srv.update() - if err != nil { - log.Errorln("Initialize NTP time failed: %s", err) - return - } - service.running = true go srv.loopUpdate() } func (srv *Service) Stop() { - srv.mu.Lock() - defer srv.mu.Unlock() - if service.running { - srv.ticker.Stop() - srv.cancel() - service.running = false - } + srv.cancel() } -func (srv *Service) Running() bool { +func (srv *Service) Offset() time.Duration { if srv == nil { - return false + return 0 } - srv.mu.Lock() - defer srv.mu.Unlock() - return srv.running + if srv.ctx.Err() != nil { + return time.Duration(srv.offset.Load()) + } + return 0 } func (srv *Service) update() error { var response *ntp.Response var err error for i := 0; i < 3; i++ { - if response, err = ntp.Exchange(context.Background(), srv.dialer, srv.server); err == nil { - break + response, err = ntp.Exchange(srv.ctx, srv.dialer, srv.server) + if err != nil { + continue } - if i == 2 { - return err + offset := response.ClockOffset + if offset > time.Duration(0) { + log.Infoln("System clock is ahead of NTP time by %s", offset) + } else if offset < time.Duration(0) { + log.Infoln("System clock is behind NTP time by %s", -offset) } - } - offset = response.ClockOffset - if offset > time.Duration(0) { - log.Infoln("System clock is ahead of NTP time by %s", offset) - } else if offset < time.Duration(0) { - log.Infoln("System clock is behind NTP time by %s", -offset) - } - if srv.syncSystemTime { - timeNow := response.Time - syncErr := setSystemTime(timeNow) - if syncErr == nil { - log.Infoln("Sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout)) - } else { - log.Errorln("Write time to system: %s", syncErr) - srv.syncSystemTime = false + srv.offset.Store(int64(offset)) + if srv.syncSystemTime { + timeNow := response.Time + syncErr := setSystemTime(timeNow) + if syncErr == nil { + log.Infoln("Sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout)) + } else { + log.Errorln("Write time to system: %s", syncErr) + srv.syncSystemTime = false + } } + return nil } - return nil + return err } func (srv *Service) loopUpdate() { + defer srv.ticker.Stop() for { + err := srv.update() + if err != nil { + log.Warnln("Sync time failed: %s", err) + } select { case <-srv.ctx.Done(): return case <-srv.ticker.C: } - err := srv.update() - if err != nil { - log.Warnln("Sync time failed: %s", err) - } } } func Now() time.Time { now := time.Now() - if service.Running() && offset.Abs() > 0 { + if offset := globalSrv.Load().Offset(); offset.Abs() > 0 { now = now.Add(offset) } return now