Skip to content

Commit 3f6c423

Browse files
committed
Merge time service to library
1 parent a74e3a1 commit 3f6c423

4 files changed

Lines changed: 101 additions & 19 deletions

File tree

common/ntp/service.go

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"github.com/sagernet/sing/common/logger"
1111
M "github.com/sagernet/sing/common/metadata"
1212
N "github.com/sagernet/sing/common/network"
13+
"github.com/sagernet/sing/service"
14+
"github.com/sagernet/sing/service/pause"
1315
)
1416

1517
const TimeLayout = "2006-01-02 15:04:05 -0700"
@@ -19,23 +21,26 @@ type TimeService interface {
1921
}
2022

2123
type Options struct {
22-
Context context.Context
23-
Server M.Socksaddr
24-
Interval time.Duration
25-
Dialer N.Dialer
26-
Logger logger.Logger
24+
Context context.Context
25+
Dialer N.Dialer
26+
Logger logger.Logger
27+
Server M.Socksaddr
28+
Interval time.Duration
29+
WriteToSystem bool
2730
}
2831

2932
var _ TimeService = (*Service)(nil)
3033

3134
type Service struct {
32-
ctx context.Context
33-
cancel common.ContextCancelCauseFunc
34-
server M.Socksaddr
35-
dialer N.Dialer
36-
logger logger.Logger
37-
ticker *time.Ticker
38-
clockOffset time.Duration
35+
ctx context.Context
36+
cancel common.ContextCancelCauseFunc
37+
dialer N.Dialer
38+
logger logger.Logger
39+
server M.Socksaddr
40+
writeToSystem bool
41+
ticker *time.Ticker
42+
clockOffset time.Duration
43+
pause pause.Manager
3944
}
4045

4146
func NewService(options Options) *Service {
@@ -47,9 +52,12 @@ func NewService(options Options) *Service {
4752
destination := options.Server
4853
if !destination.IsValid() {
4954
destination = M.Socksaddr{
50-
Fqdn: "time.google.com",
55+
Fqdn: "time.apple.com",
5156
}
5257
}
58+
if options.Logger == nil {
59+
options.Logger = logger.NOP()
60+
}
5361
if destination.Port == 0 {
5462
destination.Port = 123
5563
}
@@ -66,12 +74,14 @@ func NewService(options Options) *Service {
6674
dialer = N.SystemDialer
6775
}
6876
return &Service{
69-
ctx: ctx,
70-
cancel: cancel,
71-
server: destination,
72-
dialer: dialer,
73-
logger: options.Logger,
74-
ticker: time.NewTicker(interval),
77+
ctx: ctx,
78+
cancel: cancel,
79+
dialer: dialer,
80+
logger: options.Logger,
81+
writeToSystem: options.WriteToSystem,
82+
server: destination,
83+
ticker: time.NewTicker(interval),
84+
pause: service.FromContext[pause.Manager](ctx),
7585
}
7686
}
7787

@@ -104,6 +114,14 @@ func (s *Service) loopUpdate() {
104114
return
105115
case <-s.ticker.C:
106116
}
117+
if s.pause != nil {
118+
s.pause.WaitActive()
119+
select {
120+
case <-s.ctx.Done():
121+
return
122+
default:
123+
}
124+
}
107125
err := s.update()
108126
if err == nil {
109127
s.logger.Debug("updated time: ", s.TimeFunc()().Local().Format(TimeLayout))
@@ -119,5 +137,11 @@ func (s *Service) update() error {
119137
return err
120138
}
121139
s.clockOffset = response.ClockOffset
140+
if s.writeToSystem {
141+
writeErr := SetSystemTime(s.TimeFunc()())
142+
if writeErr != nil {
143+
s.logger.Warn("write time to system: ", writeErr)
144+
}
145+
}
122146
return nil
123147
}

common/ntp/time_stub.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//go:build !(windows || linux || darwin)
2+
3+
package ntp
4+
5+
import (
6+
"os"
7+
"time"
8+
)
9+
10+
func SetSystemTime(nowTime time.Time) error {
11+
return os.ErrInvalid
12+
}

common/ntp/time_unix.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build linux || darwin
2+
3+
package ntp
4+
5+
import (
6+
"time"
7+
8+
"golang.org/x/sys/unix"
9+
)
10+
11+
func SetSystemTime(nowTime time.Time) error {
12+
timeVal := unix.NsecToTimeval(nowTime.UnixNano())
13+
return unix.Settimeofday(&timeVal)
14+
}

common/ntp/time_windows.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ntp
2+
3+
import (
4+
"time"
5+
"unsafe"
6+
7+
"golang.org/x/sys/windows"
8+
)
9+
10+
func SetSystemTime(nowTime time.Time) error {
11+
var systemTime windows.Systemtime
12+
systemTime.Year = uint16(nowTime.Year())
13+
systemTime.Month = uint16(nowTime.Month())
14+
systemTime.Day = uint16(nowTime.Day())
15+
systemTime.Hour = uint16(nowTime.Hour())
16+
systemTime.Minute = uint16(nowTime.Minute())
17+
systemTime.Second = uint16(nowTime.Second())
18+
systemTime.Milliseconds = uint16(nowTime.UnixMilli() - nowTime.Unix()*1000)
19+
20+
dllKernel32 := windows.NewLazySystemDLL("kernel32.dll")
21+
proc := dllKernel32.NewProc("SetSystemTime")
22+
23+
_, _, err := proc.Call(
24+
uintptr(unsafe.Pointer(&systemTime)),
25+
)
26+
27+
if err != nil && err.Error() != "The operation completed successfully." {
28+
return err
29+
}
30+
31+
return nil
32+
}

0 commit comments

Comments
 (0)